package com.cloudkinto.service.platform.impl;

import cn.afterturn.easypoi.csv.entity.CsvExportParams;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.bo.order.makeshop.updateOrderAttribute.DeliveryRequestInfoForUpdate;
import com.cloudkinto.bo.order.makeshop.updateOrderAttribute.UpdateOrderAttribute;
import com.cloudkinto.common.BeanConvert;
import com.cloudkinto.common.RabbitQueueConstant;
import com.cloudkinto.common.RedisKeyConstants;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.CsvUtils;
import com.cloudkinto.common.utils.ExcelUtils;
import com.cloudkinto.common.utils.TimeUtils;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.dto.platform.PlatformOrderDetailRes;
import com.cloudkinto.dto.platform.PlatformOrderProductRes;
import com.cloudkinto.dto.platform.order.PlatOrderPageRes;
import com.cloudkinto.dto.platform.order.PlatOrderPageStaDto;
import com.cloudkinto.dto.platform.order.PlatformOrderDto;
import com.cloudkinto.dto.platform.product.ProductSysDto;
import com.cloudkinto.dto.stock.defective.SkuRackCountDto;
import com.cloudkinto.entity.*;
import com.cloudkinto.enumType.common.CountryEnum;
import com.cloudkinto.enumType.operate.OperateTypeEnum;
import com.cloudkinto.enumType.order.outbound.NormalOutboundStatusEnum;
import com.cloudkinto.enumType.order.outbound.OutboundOriginEnum;
import com.cloudkinto.enumType.stock.StockOrderTypeEnum;
import com.cloudkinto.enumType.stock.StockTypeEnum;
import com.cloudkinto.service.channel.LogisticsChannelService;
import com.cloudkinto.service.company.CompanyService;
import com.cloudkinto.service.consumer.vo.amazon.fulfillment.AmazonMarkShipConsumerReq;
import com.cloudkinto.service.consumer.vo.amazon.fulfillment.AmazonOrderFulfillment;
import com.cloudkinto.service.consumer.vo.amazon.fulfillment.AmazonOrderFulfillmentEt;
import com.cloudkinto.service.consumer.vo.makeshop.MakeShopMarkShipConsumerReq;
import com.cloudkinto.service.consumer.vo.markShip.Qoo10MarkShipConsumerReq;
import com.cloudkinto.service.consumer.vo.order.PlatOrderCancelConsumerReq;
import com.cloudkinto.service.consumer.vo.order.PlatOrderSendConsumerReq;
import com.cloudkinto.service.consumer.vo.order.PlatformOrderTrackNoEntity;
import com.cloudkinto.service.consumer.vo.order.UpdateInventoryLessReq;
import com.cloudkinto.service.consumer.vo.rakuten.BasketidModelRequest;
import com.cloudkinto.service.consumer.vo.rakuten.RakutenMarkShipConsumerReq;
import com.cloudkinto.service.consumer.vo.rakuten.RakutenOrderShippingModelRequest;
import com.cloudkinto.service.consumer.vo.rakuten.ShippingModelEntity;
import com.cloudkinto.service.consumer.vo.wowma.WowmaMarkShipConsumerReq;
import com.cloudkinto.service.consumer.vo.yahoo.YahooMarkShipConsumerReq;
import com.cloudkinto.service.mail.vo.SendMailReq;
import com.cloudkinto.service.platform.PlatformOrderProductService;
import com.cloudkinto.service.platform.PlatformOrderService;
import com.cloudkinto.service.platform.PlatformProductService;
import com.cloudkinto.service.platform.PlatformStoreService;
import com.cloudkinto.service.platform.qoo10.vo.PlatformOrderUpdateReq;
import com.cloudkinto.service.platform.qoo10.vo.Qoo10RequestReq;
import com.cloudkinto.service.platform.vo.PlatformOrderSetPushStoreReq;
import com.cloudkinto.service.platform.vo.order.*;
import com.cloudkinto.service.platform.vo.product.PlatformAddReq;
import com.cloudkinto.service.platform.vo.product.SkuAddReq;
import com.cloudkinto.service.platform.vo.wowma.WowmaMarkShipReq;
import com.cloudkinto.service.platform.vo.yahoo.YahooMarkShipReq;
import com.cloudkinto.service.regular.vo.PlatformOrderCheckReq;
import com.cloudkinto.service.stock.ProductStockFlowingService;
import com.cloudkinto.service.stock.ProductStockService;
import com.cloudkinto.service.warehouse.WarehouseService;
import com.cloudkinto.vo.channel.lc.LcChannelPageRes;
import com.cloudkinto.vo.company.CompanyPageVo;
import com.cloudkinto.vo.order.returns.OrProgressRes;
import com.cloudkinto.vo.product.ProductSkuVo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 平台订单 service实现类
 * </p>
 *
 * @author hua
 * @since 2024-12-25
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
@RequiredArgsConstructor
public class PlatformOrderServiceImpl extends ServiceImpl<PlatformOrderDao, PlatformOrderDo> implements PlatformOrderService {
    private final PlatformOrderDao dao;
    private final WarehouseService warehouseService;
    private final PlatformStoreService platformStoreService;
    private final PlatformOrderProductService platformOrderProductService;
    private final PlatformOrderProductDao platformOrderProductDao;
    private final LogisticsChannelService logisticsChannelService;
    private final PlatformProductService platformProductService;
    private final ProductDao productDao;
    private final RedisTemplate redisTemplate;
    private final RabbitTemplate rabbitTemplate;
    private final OrderOutboundDao orderOutboundDao;
    private final PlatformOrderTrackDao platformOrderTrackDao;
    private final OrderOutboundPackageDao orderOutboundPackageDao;
    private final ProductStockDao productStockDao;
    private final ProductStockService productStockService;
    private final ProductStockFlowingService productStockFlowingService;
    private final CompanyService companyService;
    private final MailAccountDao mailAccountDao;
    private final PlatformStoreDao platformStoreDao;
    private final  MailRecordDao mailRecordDao;
    private final TemplatesDao templatesdao;

    @Value("${gbc.customer}")
    private String customer;

    @Override
    public void resetStockToPlatformRecord() {
        List<PlatformStoreDo> storeDoList = platformStoreDao.selectList(null);
        for (PlatformStoreDo storeDo : storeDoList) {
            String stockRedisKey = RedisKeyConstants.PLATFORMSTOCK_KEY_PREFIX +customer +"_"+ storeDo.getId();
            redisTemplate.delete(stockRedisKey);
        }
    }


    public Integer getLastRecordedInventory(String stockRedisKey, String sku) {
        Object value = redisTemplate.opsForHash().get(stockRedisKey, sku);
        if (value == null) {
            return null;
        }
        try {
            return Integer.parseInt(value.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }
    @Override
    public void setPushStoreList(PlatformOrderSetPushStoreReq req, Long companyId) {
        redisTemplate.opsForValue().set(RedisKeyConstants.Oms_PlatformOrder_AutoCheck_List + companyId +"_"+ customer, StringUtils.join(req.getStoreIds(), "_"));
    }


    @Override
    public void resetRedisSyncTime(Boolean amazonFlag) {
        long resetTime = DateUtils.passingDateHour(new Date(), -16).getTime();
        //wowma 默认同步的近两天数据 这里可删除 可不删除 都一样
        String wowmaKey = RedisKeyConstants.orderSyncTimeSet_Wowma + customer;
        redisTemplate.delete(wowmaKey);
        //amazon
        if (amazonFlag) {
            long amazonResetTime = DateUtils.passingDateHour(new Date(), -5).getTime();
            String amazonKey = RedisKeyConstants.orderSyncTimeSet_Amazon + customer;
//            redisTemplate.delete(amazonKey);
            Set amazonRange = redisTemplate.opsForZSet().range(amazonKey, 0, -1);
            if (amazonRange != null && !amazonRange.isEmpty()) {
                for (Object storeId : amazonRange) {
                    redisTemplate.opsForZSet().add(amazonKey, storeId, amazonResetTime);
                }
            }
        }
        //yahoo
        String yahooKey = RedisKeyConstants.orderSyncTimeSet_Yahoo + customer;
//        redisTemplate.delete(yahooKey);
        Set yahooRange = redisTemplate.opsForZSet().range(yahooKey, 0, -1);
        if (yahooRange != null && !yahooRange.isEmpty()) {
            for (Object storeId : yahooRange) {
                redisTemplate.opsForZSet().add(yahooKey, storeId, resetTime);
            }
        }
        //rakuten
        String rakutenKey = RedisKeyConstants.orderSyncTimeSet_Rakuten + customer;
//        redisTemplate.delete(rakutenKey);
        Set rakutenRange = redisTemplate.opsForZSet().range(rakutenKey, 0, -1);
        if (rakutenRange != null && !rakutenRange.isEmpty()) {
            for (Object storeId : rakutenRange) {
                redisTemplate.opsForZSet().add(rakutenKey, storeId, resetTime);
            }
        }
        //qoo10
        String qoo10Key = RedisKeyConstants.orderSyncTimeSet_Qoo10 + customer;
//        redisTemplate.delete(qoo10Key);
        Set qoo10Range = redisTemplate.opsForZSet().range(qoo10Key, 0, -1);//Integer
        if (qoo10Range != null && !qoo10Range.isEmpty()) {
            for (Object storeId : qoo10Range) {
                redisTemplate.opsForZSet().add(qoo10Key, storeId, resetTime);
            }
        }
        //makeshop
//        String makeshopKey = RedisKeyConstants.orderSyncTimeSet_Makeshop + customer;
//        redisTemplate.delete(makeshopKey);
        //shopify
        String shopifyKey = RedisKeyConstants.orderSyncTimeSet_Shopify + customer;
//        redisTemplate.delete(shopifyKey);
        Set shopifyRange = redisTemplate.opsForZSet().range(shopifyKey, 0, -1);
        if (shopifyRange != null && !shopifyRange.isEmpty()) {
            for (Object storeId : shopifyRange) {
                redisTemplate.opsForZSet().add(shopifyKey, storeId, resetTime);
            }
        }
    }

    @Override
    public List<Long> getAutoCheckStoreList(Long companyId) {
        Object storeStr = redisTemplate.opsForValue().get(RedisKeyConstants.Oms_PlatformOrder_AutoCheck_List +companyId +"_" + customer);
        if (storeStr == null || Objects.equals(storeStr, "")) {
            return new ArrayList<>();
        }
        String[] split = storeStr.toString().split("_");
        return Arrays.stream(split).map(Long::parseLong).collect(Collectors.toList());
    }

//    @Override
//    public void updateMarkStatusByNo(List<String> platOrderNo, Integer markShipmentStatus, String failReason) {
//        if (platOrderNo == null || platOrderNo.isEmpty()) {
//            return;
//        }
//        LambdaUpdateWrapper<PlatformOrderDo> updateWrapper = new LambdaUpdateWrapper<PlatformOrderDo>();
//        updateWrapper.in(PlatformOrderDo::getPlatformOrderNo, platOrderNo);
//        updateWrapper.set(StringUtils.isNotBlank(failReason), PlatformOrderDo::getMarkShipmentFailReason, failReason);
//        updateWrapper.set(PlatformOrderDo::getMarkShipmentStatus, markShipmentStatus);
//        updateWrapper.set(PlatformOrderDo::getMarkShipmentTime, new Date());
//        this.update(updateWrapper);
//    }


    @Override
    public void updateMarkStatus(List<Long> ids, Integer markShipmentStatus, String failReason) {
        this.updateMarkStatusForFinish(ids, markShipmentStatus, failReason, null);
    }


    @Override
    public void updateMarkStatusForFinish(List<Long> ids, Integer markShipmentStatus, String failReason, String platformCode) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        boolean flag = markShipmentStatus == 3 && StringUtils.isNotBlank(platformCode) && (StaticDict.Store_PlatformCode.Yahoo.getValue().equals(platformCode) || StaticDict.Store_PlatformCode.Wowma.getValue().equals(platformCode)|| StaticDict.Store_PlatformCode.Makeshop.getValue().equals(platformCode));
        LambdaUpdateWrapper<PlatformOrderDo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(PlatformOrderDo::getId, ids);
        updateWrapper.set(StringUtils.isNotBlank(failReason), PlatformOrderDo::getMarkShipmentFailReason, failReason);
        updateWrapper.set(PlatformOrderDo::getMarkShipmentStatus, markShipmentStatus);
        updateWrapper.set(flag, PlatformOrderDo::getMarkFinishStatus, 5);
        updateWrapper.set(markShipmentStatus == 1 || markShipmentStatus == 3, PlatformOrderDo::getMarkShipmentFailReason, null);
        updateWrapper.set(PlatformOrderDo::getMarkShipmentTime, new Date());
        this.update(updateWrapper);
    }

    @Override
    public Object update(Object req, Long userId) {
        /*PlatformOrderDo entityDo = dao.selectById(req.getId());
        BeanUtils.copyProperties(req, entityDo);
        handlerUpdateBefore(entityDo, userId);
        dao.updateById(entityDo);
        return handlerUpdateAfter(entityDo);*/
        return null;
    }


    @Override
    public int delete(Long id, Long userId) {
        PlatformOrderDo entityDo = dao.selectById(id);
        handlerDeleteBefore(entityDo, userId);
        return dao.deleteById(id);
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(PlatformOrderDo entityDo, Long userId) {

    }

    @Override
    public Object detail(Long id, Long companyId) {
        Map<String, Object> param = new HashMap<>();
        param.put("id", id);
        param.put("companyId", companyId);
        List<PlatOrderPageRes> list = dao.getList(param);
        if (list.isEmpty()) {
            throw new BizException(SysConstant.No_Data);
        }
        PlatOrderPageRes entityDo = list.get(0);
        PlatformOrderDetailRes res = new PlatformOrderDetailRes();
        BeanUtils.copyProperties(entityDo, res);
        res.setProducts(platformOrderProductService.getProducts(id));
        res.setProgress(this.setProgressList(res));
        return (res);
    }

    public List<OrProgressRes> setProgressList(PlatOrderPageRes res) {
        List<OrProgressRes> progressList = new ArrayList<>();
        progressList.add(new OrProgressRes("create", "platformOrder_create", res.getPlatformOrderNo(), res.getCreateTime(), res.getCreateByName()));
        progressList.add(new OrProgressRes("audit", "platformOrder_audit", res.getPlatformOrderNo(), res.getAuditTime(), res.getAuditByName()));
        progressList.add(new OrProgressRes("ship", "platformOrder_ship", res.getPlatformOrderNo(), res.getShipTime(), res.getShipByName()));
        progressList.add(new OrProgressRes("cancel", "platformOrder_cancel", res.getPlatformOrderNo(), res.getCancelTime(), res.getCancelByName()));
        return progressList;
    }


    @Override
    public void updatePlatformOrder(PlatformOrderUpdateReq req, Long userId, Long companyId) {
        PlatformOrderDo orderDo = baseMapper.selectById(req.getId());
        if (orderDo == null || !orderDo.getCompanyId().equals(companyId)) {
            return;
        }
        if (!StaticDict.Platform_Order_Status.Zero.getValue().equals(orderDo.getStatus())) {
            return;
        }
        if (req.getProducts() == null || req.getProducts().isEmpty()) {
            return;
        }
        long count = req.getProducts().stream().filter(item -> item.getSkuType() == 1 || item.getProductId() == null || item.getQty() == 1).count();
        if (count == 0) {
            return;
        }
        //邮编的正则表达式 数字和 -
        if (!req.getPostcode().matches("^[0-9-]+$")) {
            throw new BizException(SysConstant.Cm_Order_Check_CodeForm);
        }


        List<PlatformOrderProductDo> productList = new ArrayList<>();

        StringBuilder platformSkuBuilder = new StringBuilder();
        StringBuilder systemSkuBuilder = new StringBuilder();

        for (PlatformOrderProductRes reqProduct : req.getProducts()) {
            PlatformOrderProductDo platItem = new PlatformOrderProductDo();
            platItem.setOrderId(req.getId());
            platItem.setPlatformOrderNo(orderDo.getPlatformOrderNo());
            platItem.setPlatformSku(reqProduct.getPlatformSku());
            platItem.setPlatformProductName(reqProduct.getPlatformProductName());
            platItem.setPlatformQty(reqProduct.getPlatformQty());
            platItem.setSku(reqProduct.getSku());
            platItem.setQty(reqProduct.getQty());
            platItem.setSkuType(reqProduct.getSkuType());
            platItem.setItemAmount(reqProduct.getItemAmount());
            platItem.setCurrencyCode(CountryEnum.JP.getCurrency());
            if (StringUtils.isNotBlank(reqProduct.getSku())) {
                platItem.setProductId(reqProduct.getProductId());
            }

            if (StringUtils.isNotBlank(reqProduct.getPlatformSku())) {
                if (StringUtils.isNotBlank(platformSkuBuilder.toString())) {
                    platformSkuBuilder.append(";");
                }
                platformSkuBuilder.append(platItem.getPlatformSku()).append("*").append(platItem.getPlatformQty());
            }
            if (StringUtils.isNotBlank(reqProduct.getSku())) {
                if (StringUtils.isNotBlank(systemSkuBuilder.toString())) {
                    systemSkuBuilder.append(";");
                }
                systemSkuBuilder.append(platItem.getSku()).append("*").append(platItem.getQty());
            }
            productList.add(platItem);
        }
        this.update(new LambdaUpdateWrapper<PlatformOrderDo>()
                .eq(PlatformOrderDo::getId, req.getId())
                .set(PlatformOrderDo::getPlatformSku, platformSkuBuilder.toString())
                .set(PlatformOrderDo::getSku, systemSkuBuilder.toString())
                .set(PlatformOrderDo::getReceiver, req.getReceiver())
                .set(PlatformOrderDo::getTelephone, req.getTelephone())
                .set(PlatformOrderDo::getPostcode, req.getPostcode())
                .set(PlatformOrderDo::getCityCode, req.getCityCode())
                .set(PlatformOrderDo::getDistrict, req.getDistrict())
                .set(PlatformOrderDo::getHouseNum, req.getHouseNum())
                .set(PlatformOrderDo::getAddressOne, req.getAddressOne())
                .set(PlatformOrderDo::getAddressTwo, req.getAddressTwo())
                .set(PlatformOrderDo::getAddressTri, req.getAddressTri())
                .set(PlatformOrderDo::getDeliveryDate, req.getDeliveryDate())
                .set(PlatformOrderDo::getDeliveryTimeName, req.getDeliveryTimeName())
                .set(PlatformOrderDo::getUpdateTime, new Date())
                .set(PlatformOrderDo::getUpdateBy, userId)
        );
        platformOrderProductDao.delete(new LambdaQueryWrapper<PlatformOrderProductDo>()
                .eq(PlatformOrderProductDo::getOrderId, req.getId()));
        platformOrderProductDao.insertPlatformOrderItems(productList);

        List<OperateRecordDo> operateRecordDos = new ArrayList<>();
        OperateRecordDo operateRecordDo = new OperateRecordDo(req.getId(), OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_Update_Manual, userId, new Date(), "");
        operateRecordDos.add(operateRecordDo);
        rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(operateRecordDos));
    }

    @Override
    public SingleResult pageInit(Long companyId, Long tenantId) {
        Map<String, Object> result = new HashMap<>();
        List<Map<Object, Object>> orderReturnStatus = StaticDict.getPlatform_Order_Status();
        Map<Object, Object> map = new HashMap<>();
        map.put("id", null);
        map.put("name", "全部");
        orderReturnStatus.add(0, map);
        result.put("returnStatus", orderReturnStatus);
        result.put("warehouseList", warehouseService.getWarehouseCompany(companyId, tenantId));
        result.put("storeList", platformStoreService.getList(companyId));
        result.put("channelList", logisticsChannelService.getLcList(null, companyId, tenantId));
        result.put("platformCode", StaticDict.getStore_PlatformCode());
        Object autoSubmit = redisTemplate.opsForValue().get(RedisKeyConstants.Oms_PlatformOrder_AutoSubmit_ + companyId);
        result.put("autoSubmit", autoSubmit == null ? 1 : autoSubmit);
        //获取目前开启自动同步的店铺
        result.put("autoCheckStoreList", this.getAutoCheckStoreList(companyId));
        //审核失败原因
        result.put("autoCheckReason", StaticDict.getPlatformOrder_Audit_Code());
        return SingleResult.success(result);
    }

    @Override
    public List<PlatOrderPageRes> getList(Map<String, Object> map) {
        return dao.getList(map);
    }

    @Override
    public PageResult<PlatOrderPageRes> getListPage(Map<String, Object> map) {
        IPage<PlatOrderPageRes> page = pageInit(map);
        page = dao.getList(page, map);
        //将page转为list类型
        String companyId = map.get("companyId") == null ? null : map.get("companyId").toString();
        Map<Long, Long> finalMailStoreMap = this.getMailStoreMap(companyId);
        page.getRecords().stream().filter(item -> item.getStoreId() != null).forEach(item -> {
            Long mailId = finalMailStoreMap.get(item.getStoreId());
            if (mailId != null) {
                item.setDefaultSendMailId(mailId); // 假设类型为Long
            }
        });

        return new PageResult<PlatOrderPageRes>(page.getRecords(), (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
    }



    public Map<Long, Long> getMailStoreMap(String companyId) {
        String mailAccountStoreRedisKey = RedisKeyConstants.MailAccountStoreKey + customer + "_" +companyId;
        Object mailStoreObject = redisTemplate.opsForValue().get(mailAccountStoreRedisKey);
        Map<Long, Long> mailStoreMap = new HashMap<>();
        if (mailStoreObject == null) {
            mailStoreMap = mailAccountDao.selectList(new LambdaQueryWrapper<MailAccountDo>().select(MailAccountDo::getId, MailAccountDo::getStoreId)
                            .eq(MailAccountDo::getCompanyId, companyId))
                    .stream().collect(Collectors.toMap(MailAccountDo::getStoreId, MailAccountDo::getId, (v1, v2) -> v1));
            // 可选：将数据库查询结果缓存到Redis，避免重复查询
            String s = this.serializeMap(mailStoreMap);
            if (s != null) {
                redisTemplate.opsForValue().set(mailAccountStoreRedisKey, s);
                // 建议设置过期时间，避免缓存长期有效
                redisTemplate.expire(mailAccountStoreRedisKey, 1, TimeUnit.HOURS);
            }
        }
        else {
            mailStoreMap = this.deserializeMap(mailStoreObject.toString());
            if (mailStoreMap == null) {
                mailStoreMap = mailAccountDao.selectList(new LambdaQueryWrapper<MailAccountDo>().select(MailAccountDo::getId, MailAccountDo::getStoreId))
                        .stream().collect(Collectors.toMap(MailAccountDo::getStoreId, MailAccountDo::getId, (v1, v2) -> v1));
            }
        }
        return mailStoreMap;
    }

    private final ObjectMapper objectMapper = new ObjectMapper ();


    //将 Map<Long, Long> 序列化为 JSON 字符串
    private String serializeMap (Map<Long, Long> map) {
        String s = null;
        try {
            s = objectMapper.writeValueAsString(map);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage());
        }
        return s;
    }

    /**
     将 JSON 字符串反序列化为 Map<Long, Long>
     */
    private Map<Long, Long> deserializeMap (String json) {
        Map<Long, Long> map = null;
        try {
            map = objectMapper.readValue (json, Map.class);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage());
        }
        return map;
    }


    @Override
    public PageResult getListPageMailSendStatus(Map<String, Object> map) {
        // 初始化分页对象
        IPage<MailRecordDo> page = new Page<>();
       page.setSize(map.get("pageSize") != null ? Long.parseLong(map.get("pageSize").toString()) : 10);
       page.setCurrent(map.get("current") != null ? Long.parseLong(map.get("current").toString()) : 1);
        //从templatedao中查询它的id和模板名所有的映射成map<integer,String>
        Map<Integer, String> templateMap = templatesdao.selectList(new LambdaQueryWrapper<TemplatesDo>()
                        .select(TemplatesDo::getId, TemplatesDo::getName))
                .stream()
                .collect(Collectors.toMap(
                        TemplatesDo::getId,
                        TemplatesDo::getName,
                        (existing, replacement) -> existing // 如果有重复，保留第一个
                ));
        Map<Long, String> storeMap =    platformStoreDao.selectList(new LambdaQueryWrapper<PlatformStoreDo>()
                .select(PlatformStoreDo::getId, PlatformStoreDo::getStoreName))
                .stream()
                .collect(Collectors.toMap(
                        PlatformStoreDo::getId,
                        PlatformStoreDo::getStoreName,
                        (existing, replacement) -> existing // 如果有重复，保留第一个
                ));

        //构建查询条件
        LambdaQueryWrapper<MailRecordDo> queryWrapper = getMailRecordDoLambdaQueryWrapper(map);
        IPage<MailRecordDo> mailRecordDoIPage = mailRecordDao.selectPage(page, queryWrapper);
        if(!mailRecordDoIPage.getRecords().isEmpty()) {
            mailRecordDoIPage = handlePage(mailRecordDoIPage, templateMap, storeMap);
        }

        // 构造返回结果
        PageResult result = new PageResult(
                mailRecordDoIPage.getRecords(),
                (int) page.getCurrent(),
                (int) page.getSize(),
                (int) mailRecordDoIPage.getTotal(),
                (int) mailRecordDoIPage.getPages()
        );

        return result;
    }

    private  LambdaQueryWrapper<MailRecordDo> getMailRecordDoLambdaQueryWrapper(Map<String, Object> map) {
        LambdaQueryWrapper<MailRecordDo> queryWrapper = new LambdaQueryWrapper<>();
        if(map.get("status") != null) {
            queryWrapper.eq(MailRecordDo::getSendStatus, map.get("status"));
        }
        if(map.get("platformCode")!=null)
        {
            queryWrapper.eq(MailRecordDo::getPlatformCode, map.get("platformCode"));
        }
        if(map.get("receiver")!=null)
        {
            queryWrapper.like(MailRecordDo::getRecipient, map.get("receiver"));
        }
        if(map.get("shop")!=null)
        {
            queryWrapper.eq(MailRecordDo::getStoreId, map.get("shop"));
        }
        if(map.get("templateName") != null)
        {
            queryWrapper.eq(MailRecordDo::getTemplateId, map.get("templateName"));
        }
        if(map.get("sendMethod") != null)
        {
            queryWrapper.eq(MailRecordDo::getSendMethod, map.get("sendMethod"));
        }
        if(map.get("platformOrderNo")!=null)
        {
            queryWrapper.like(MailRecordDo::getPlatformOrderNo, map.get("platformOrderNo"));

        }
        /*if(map.get("sendTime")!=null)
        {
            queryWrapper.ge(MailRecordDo::getSendTime, map.get("sendTime"));
        }*/

        // 执行分页查询,倒序排序
        queryWrapper.orderByDesc(MailRecordDo::getSendTime);
        return queryWrapper;
    }

    private IPage<MailRecordDo> handlePage(IPage<MailRecordDo> mailRecordDoIPage, Map<Integer, String> templateMap,Map<Long , String>storeMap) {

        MailRecordDo mailRecordDo = mailRecordDoIPage.getRecords().get(0);
        Long storeId = mailRecordDo.getStoreId();
        String s = storeMap.get(storeId);


        mailRecordDoIPage.getRecords().forEach(item -> {

            item.setTemplateName(templateMap.getOrDefault(Math.toIntExact(item.getTemplateId()), "未知模板"));
            item.setShop(storeMap.getOrDefault(item.getStoreId(), "未知店铺"));
        });
        return mailRecordDoIPage;
    }   


    private IPage<PlatOrderPageRes> pageInit(Map<String, Object> map) {
        IPage<PlatOrderPageRes> page = new Page<>();
        page.setSize(map.get("pageSize") != null ? Long.parseLong(map.get("pageSize").toString()) : 10);
        page.setCurrent(map.get("current") != null ? Long.parseLong(map.get("current").toString()) : 1);
        return page;
    }


    @Override
    public Map<String, Object> statusStatistics(Map<String, Object> map) {
        Map<String, Object> resultMap = new HashMap<>();
        map.remove("status");
        map.remove("reserveFlag");
        StringBuilder sendStatistics = new StringBuilder("PlatformOrder_status;");
        for (String mapKey : map.keySet()) {
            if (map.get(mapKey) == null || StringUtils.isBlank(map.get(mapKey).toString())) {
                continue;
            }
            if (sendStatistics.length() > 0) {
                sendStatistics.append(";");
            }
            sendStatistics.append(mapKey).append(":").append(map.get(mapKey));
        }
        Map<String, Integer> sendStatisticsMap = new HashMap<>();
        Object finishData = redisTemplate.opsForValue().get(sendStatistics.toString());
        if (finishData != null) {
            //获取期间发货数量
            sendStatisticsMap = (Map<String, Integer>) finishData;
            map.put("redisStatusList", Arrays.asList(0,1,2,4,5));
        }
        List<PlatOrderPageStaDto> platOrderList = dao.statusStatistics(map);
        Map<Integer, Integer> collect = platOrderList.stream().filter(i -> i.getStatus() != null).collect(Collectors.toMap(PlatOrderPageStaDto::getStatus, PlatOrderPageStaDto::getCount, Integer::sum));
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (StaticDict.Platform_Order_Status value : StaticDict.Platform_Order_Status.values()) {
            Map<String, Object> m = new HashMap<>();
            m.put("id", value.getValue());
            m.put("name", value.getText());
            Integer i = collect.get(value.getValue()) == null ? 0 : collect.get(value.getValue());
            if (value.getValue() == 3) {
                if (finishData == null) {
                    sendStatisticsMap.put("finishCount", i);
                }
                else {
                    //已发货数据缓存
                    i += sendStatisticsMap.get("finishCount");
                }
            }
            m.put("sum", i);
            resultList.add(m);
        }
        resultMap.put("status", resultList);
        //根据订单类型分
        List<Map<String, Object>> flagList = new ArrayList<>();

        Map<Integer, Integer> flagCollect = platOrderList.stream().filter(i -> i.getReserveFlag() != null).collect(Collectors.toMap(PlatOrderPageStaDto::getReserveFlag, PlatOrderPageStaDto::getCount, Integer::sum));
        for (StaticDict.Order_CM_Order_Type value : StaticDict.Order_CM_Order_Type.values()) {
            Map<String, Object> m = new HashMap<>();
            m.put("id", value.getValue());
            m.put("name", value.getText());
            Integer i = flagCollect.get(value.getValue()) == null ? 0 : flagCollect.get(value.getValue());
            if (finishData != null){
                i += sendStatisticsMap.get(value.getValue() + "_count");
            }
            m.put("sum", i);
            flagList.add(m);
        }
        resultMap.put("flag", flagList);

        if (finishData == null) {
            Map<Integer, Integer> finishFlagCollect = platOrderList.stream().filter(i -> i.getReserveFlag() != null && Objects.equals(i.getStatus(), 3)).collect(Collectors.toMap(PlatOrderPageStaDto::getReserveFlag, PlatOrderPageStaDto::getCount, Integer::sum));
            for (StaticDict.Order_CM_Order_Type value : StaticDict.Order_CM_Order_Type.values()) {
                Integer i = finishFlagCollect.get(value.getValue()) == null ? 0 : finishFlagCollect.get(value.getValue());
                sendStatisticsMap.put(value.getValue() + "_count", i);
            }
            redisTemplate.opsForValue().set(sendStatistics.toString(), sendStatisticsMap, 60 * 10, TimeUnit.SECONDS);
        }
        return resultMap;
    }

    /**
     * 取消状态可以变成待处理
     */
    @Override
    public void updateToDeal(MakeShipReq req, Long userId, Long companyId) {
        if (req.getIds().isEmpty()) {
            return;
        }
        List<PlatformOrderDo> orderDos = dao.selectList(new LambdaQueryWrapper<PlatformOrderDo>().in(PlatformOrderDo::getId, req.getIds())
                .eq(PlatformOrderDo::getCompanyId, companyId)
                .in(PlatformOrderDo::getStatus, StaticDict.Platform_Order_Status.Three.getValue(), StaticDict.Platform_Order_Status.Four.getValue(), StaticDict.Platform_Order_Status.Five.getValue()));
        if (orderDos.isEmpty()) {
            return;
        }
        List<Long> orderIds = orderDos.stream().map(PlatformOrderDo::getId).collect(Collectors.toList());
        LambdaUpdateWrapper<PlatformOrderDo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(PlatformOrderDo::getId, orderIds);
        updateWrapper.set(PlatformOrderDo::getSendWhId, null);
        updateWrapper.set(PlatformOrderDo::getChannelId, null);
        updateWrapper.set(PlatformOrderDo::getCancelTime, null);
        updateWrapper.set(PlatformOrderDo::getCancelBy, null);
        updateWrapper.set(PlatformOrderDo::getShipTime, null);
        updateWrapper.set(PlatformOrderDo::getShipBy, null);
        updateWrapper.set(PlatformOrderDo::getExceptionCause, null);
        updateWrapper.set(PlatformOrderDo::getStatus, StaticDict.Platform_Order_Status.Zero.getValue());
        updateWrapper.set(PlatformOrderDo::getUpdateTime, new Date());
        updateWrapper.set(PlatformOrderDo::getUpdateBy, userId);
        this.update(updateWrapper);
        platformOrderTrackDao.delete(new LambdaQueryWrapper<PlatformOrderTrackDo>()
                .in(PlatformOrderTrackDo::getOrderId, req.getIds()));
        //如果是已发货状态 回滚库存
        //操作日志
        List<OperateRecordDo> operateRecordDos = new ArrayList<>();
        for (Long orderId : orderIds) {
            OperateRecordDo operateRecordDo = new OperateRecordDo(orderId, OperateTypeEnum.PlatformOrder.getValue(),
                    SysConstant.platformOrder_UpdateTo_Deal,
                    userId, new Date(), null);
            operateRecordDos.add(operateRecordDo);
        }
        if (!operateRecordDos.isEmpty()) {
            List<List<OperateRecordDo>> recordPartition = ListUtil.partition(operateRecordDos, 3000);
            for (List<OperateRecordDo> partList : recordPartition) {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
            }
        }
    }


    /**
     * 标记为已发货
     */
    @Override
    public List<UpdateToFinishErrorRes> updateToFinish(MakeShipReq req, Long userId, Long companyId, Long tenantId) {
        if (req.getIds().isEmpty()) {
            return new ArrayList<>();
        }
        List<PlatformOrderDo> orderDos = dao.selectList(new LambdaQueryWrapper<PlatformOrderDo>().in(PlatformOrderDo::getId, req.getIds())
                .eq(PlatformOrderDo::getCompanyId, companyId)
                .in(PlatformOrderDo::getStatus, Arrays.asList(StaticDict.Platform_Order_Status.Zero.getValue(),
                        StaticDict.Platform_Order_Status.One.getValue(),
                        StaticDict.Platform_Order_Status.Two.getValue()
                )));
        if (orderDos.isEmpty()) {
            return new ArrayList<>();
        }
        Set<Long> toMatchOrderIds = new HashSet<>();
        List<PlatformOrderProductDo> allProductList = new ArrayList<>();
        Map<Long, List<PlatformOrderDo>> orderMap = orderDos.stream().collect(Collectors.groupingBy(PlatformOrderDo::getStoreId));
        for (Long storeId : orderMap.keySet()) {
            List<Long> orderIds = orderMap.get(storeId).stream().map(PlatformOrderDo::getId).collect(Collectors.toList());
            List<PlatformOrderProductDo> orderProductDos = platformOrderProductService.list(new LambdaQueryWrapper<PlatformOrderProductDo>()
                    .in(PlatformOrderProductDo::getOrderId, orderIds));
            List<PlatformOrderProductDo> toMatch = orderProductDos.stream().filter(i -> i.getSkuType() == 1 && i.getProductId() == null).collect(Collectors.toList());
            List<PlatformOrderProductDo> matchedList = orderProductDos.stream().filter(i -> !(i.getSkuType() == 1 && i.getProductId() == null)).collect(Collectors.toList());
            toMatchOrderIds.addAll(toMatch.stream().map(PlatformOrderProductDo::getOrderId).collect(Collectors.toList()));
            //先去匹配sku
            this.matchSystemSku(toMatch, storeId, companyId, tenantId);
            for (PlatformOrderProductDo productDo : toMatch) {
                if (productDo.getProductId() == null) {
                    continue;
                }
                if (productDo.getId() == null) {
                    platformOrderProductDao.insert(productDo);
                } else {
                    platformOrderProductDao.updateById(productDo);
                }
            }
            allProductList.addAll(toMatch);
            allProductList.addAll(matchedList);
        }
        if (!toMatchOrderIds.isEmpty()) {
            Map<Long, List<PlatformOrderProductDo>> productOrderMap = allProductList.stream().collect(Collectors.groupingBy(PlatformOrderProductDo::getOrderId));
            for (Long orderId : productOrderMap.keySet()) {
                if (!toMatchOrderIds.contains(orderId)) {
                    continue;
                }
                StringBuilder mergeOrderSku = new StringBuilder();
                for (PlatformOrderProductDo productDo : productOrderMap.get(orderId)) {
                    if (productDo.getProductId() == null || StringUtils.isBlank(productDo.getSku())) {
                        continue;
                    }
                    if (StringUtils.isNotBlank(mergeOrderSku.toString())) {
                        mergeOrderSku.append(";");
                    }
                    mergeOrderSku.append(productDo.getSku()).append("*").append(productDo.getQty());
                }
                if (StringUtils.isBlank(mergeOrderSku.toString())) {
                    continue;
                }
                if (mergeOrderSku.length() > 100) {
                    mergeOrderSku.delete(100, mergeOrderSku.length());
                }
                LambdaUpdateWrapper<PlatformOrderDo> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(PlatformOrderDo::getId, orderId);
                updateWrapper.set(PlatformOrderDo::getSku, mergeOrderSku.toString());
                this.update(updateWrapper);
            }
        }
        if ("kk".equals(customer)) {
            if (req.getWhId() != null) {
                return this.updateToFinishKK(req, orderDos, allProductList, userId, companyId, tenantId);
            } else {
                List<UpdateToFinishErrorRes> res = new ArrayList<>();
                orderDos.stream().filter(i -> i.getSendWhId() == null).forEach(i -> res.add(new UpdateToFinishErrorRes(i.getPlatformOrderNo(), "无发货仓库")));
                Map<Long, List<PlatformOrderDo>> collect = orderDos.stream().filter(i -> i.getSendWhId() != null).collect(Collectors.groupingBy(PlatformOrderDo::getSendWhId));
                for (Long sendWhId : collect.keySet()) {
                    MakeShipReq shipReq = new MakeShipReq();
                    shipReq.setWhId(sendWhId);
                    shipReq.setIds(collect.get(sendWhId).stream().map(PlatformOrderDo::getId).collect(Collectors.toList()));
                    res.addAll(this.updateToFinishKK(shipReq, collect.get(sendWhId), allProductList, userId, companyId, tenantId));
                }
                return res;
            }
        }
        List<Long> orderIds = orderDos.stream().map(PlatformOrderDo::getId).collect(Collectors.toList());
        LambdaUpdateWrapper<PlatformOrderDo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(PlatformOrderDo::getId, orderIds);
        updateWrapper.set(PlatformOrderDo::getStatus, StaticDict.Platform_Order_Status.Three.getValue());
        updateWrapper.set(PlatformOrderDo::getShipTime, new Date());
        updateWrapper.set(PlatformOrderDo::getShipBy, userId);
        updateWrapper.set(PlatformOrderDo::getMarkShipmentStatus, 4);//不标发
        updateWrapper.set(PlatformOrderDo::getUpdateTime, new Date());
        updateWrapper.set(PlatformOrderDo::getUpdateBy, userId);
        this.update(updateWrapper);

        List<OperateRecordDo> operateRecordDos = new ArrayList<>();
        for (Long orderId : orderIds) {
            OperateRecordDo operateRecordDo = new OperateRecordDo(orderId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkShip_Manual,
                    userId, new Date(), "");
            operateRecordDos.add(operateRecordDo);
        }
        //操作记录
        if (!operateRecordDos.isEmpty()) {
            List<List<OperateRecordDo>> partition = ListUtil.partition(operateRecordDos, 3000);
            for (List<OperateRecordDo> partList : partition) {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
            }
        }

        return new ArrayList<>();
    }


    public List<UpdateToFinishErrorRes> updateToFinishKK(MakeShipReq req, List<PlatformOrderDo> orderDos, List<PlatformOrderProductDo> orderProductDos, Long userId, Long companyId, Long tenantId) {
        //kk的需要扣库存
        Map<Long, List<PlatformOrderProductDo>> productMap = orderProductDos.stream().collect(Collectors.groupingBy(PlatformOrderProductDo::getOrderId));
        List<UpdateToFinishErrorRes> errorResList = new ArrayList<>();
        List<Long> successId = new ArrayList<>();
        List<Long> productIds = new ArrayList<>();
        productMap.values().forEach(list -> list.stream().filter(product -> product.getProductId() != null).forEach(product -> productIds.add(product.getProductId())));
        Map<Long, List<SkuRackCountDto>> rackCountMap = new HashMap<>();
        if (!productIds.isEmpty()) {
            //根据产品ids获取库存
            rackCountMap = productStockDao.getSkuRackCountList(productIds, req.getWhId(), companyId).stream().collect(Collectors.groupingBy(SkuRackCountDto::getProductId));
        }
        //記錄庫存扣多少個
        Map<String, Integer> productRackMap = new HashMap<>();
        List<ProductStockFlowingDo> flowingDoList = new ArrayList<>();
        for (int i = 0; i < orderDos.size(); i++) {
            PlatformOrderDo orderDo = orderDos.get(i);
            List<PlatformOrderProductDo> products = productMap.get(orderDo.getId());
            if (products == null) {
                successId.add(orderDo.getId());
                orderDos.remove(i);
                i--;
                continue;
            }
            long count = products.stream().filter(orderProductDo -> orderProductDo.getProductId() == null).count();
            if (count > 0) {
                errorResList.add(new UpdateToFinishErrorRes(orderDo.getPlatformOrderNo(), "存在未匹配的SKU"));
                orderDos.remove(i);
                i--;
                continue;
            }
            //判断库存够不够
            Map<Long, Integer> orderProductMap = products.stream().collect(Collectors.toMap(PlatformOrderProductDo::getProductId, PlatformOrderProductDo::getQty, Integer::sum));
            boolean stockFlag = false;
            for (Long productId : orderProductMap.keySet()) {
                List<SkuRackCountDto> skuRackCountDtos = rackCountMap.get(productId);
                if (skuRackCountDtos == null || skuRackCountDtos.stream().filter(dto -> dto.getQuantity() > 0).mapToInt(SkuRackCountDto::getQuantity).sum() < orderProductMap.get(productId)) {
                    stockFlag = true;
                    break;
                }
            }
            if (stockFlag) {
                errorResList.add(new UpdateToFinishErrorRes(orderDo.getPlatformOrderNo(), "产品库存不足"));
                orderDos.remove(i);
                i--;
                continue;
            }
            for (Long productId : orderProductMap.keySet()) {
                int quantity = orderProductMap.get(productId);
                List<SkuRackCountDto> skuRackCountDtos = rackCountMap.get(productId);
                for (SkuRackCountDto dto : skuRackCountDtos) {
                    if (dto.getQuantity() <= 0) {
                        continue;
                    }
                    int bookQuantity = 0;
                    if (quantity >= dto.getQuantity()) {
                        productRackMap.merge(productId + "_" + dto.getStockRackId() + "_" + dto.getId(), dto.getQuantity(), Integer::sum);
                        bookQuantity = dto.getQuantity();
                        quantity -= dto.getQuantity();
                        dto.setQuantity(0);
                    } else {
                        productRackMap.merge(productId + "_" + dto.getStockRackId() + "_" + dto.getId(), quantity, Integer::sum);
                        bookQuantity = quantity;
                        dto.setQuantity(dto.getQuantity() - quantity);
                        quantity = 0;
                    }
                    //庫存流水
                    ProductStockFlowingDo flowingDo = new ProductStockFlowingDo();
                    flowingDo.setSku(dto.getSku());
                    flowingDo.setCompanyId(companyId);
                    flowingDo.setRackId(dto.getRackId());
                    flowingDo.setWarehouseId(req.getWhId());
                    flowingDo.setRackId(dto.getRackId());
                    flowingDo.setStockAttribute(0);
                    flowingDo.setBookQuantity(-bookQuantity);
                    flowingDo.setNoteNo(orderDo.getPlatformOrderNo());
                    flowingDo.setOrderType(StockOrderTypeEnum.PlatformOrder.getValue());
                    flowingDo.setTips("平台订单标记发货扣库存");
                    flowingDo.setTenantId(tenantId);
                    flowingDo.setType(StockTypeEnum.one.getValue());
                    String batchNo = DateUtils.dateFormatToString(dto.getCreateTime(), "yyyyMMdd");
                    flowingDo.setInnerBatchNo("BN" + batchNo);
                    flowingDo.setCloseQty(skuRackCountDtos.stream().filter(sss -> sss.getQuantity() > 0 || sss.getLockQuantity() > 0).mapToInt(sss -> sss.getQuantity() + sss.getLockQuantity()).sum());
                    flowingDoList.add(flowingDo);
                    if (quantity == 0) {
                        break;
                    }
                }
            }
            successId.add(orderDo.getId());
        }
        //扣库存
        for (String string : productRackMap.keySet()) {
            String[] split = string.split("_");
            productStockService.updateStockById(Long.valueOf(split[2]), Long.valueOf(split[1]), productRackMap.get(string));
        }
        //插入库存流水
        if (!flowingDoList.isEmpty()) {
            productStockFlowingService.insertBatch(flowingDoList);
        }
        if (!successId.isEmpty()) {
            this.lambdaUpdate().in(PlatformOrderDo::getId, successId).set(PlatformOrderDo::getStatus, StaticDict.Platform_Order_Status.Three.getValue())
                    .set(req.getWhId() != null, PlatformOrderDo::getSendWhId, req.getWhId())
                    .set(PlatformOrderDo::getShipTime, new Date())
                    .set(PlatformOrderDo::getShipBy, userId)
//                    .set(PlatformOrderDo::getMarkShipmentStatus, 4)
                    .setSql("mark_shipment_status = (case when track_no is not null and track_no != '' then 5 else 4 end) ")
                    .set(PlatformOrderDo::getUpdateTime, new Date()).set(PlatformOrderDo::getUpdateBy, userId).update();
            List<OperateRecordDo> operateRecordDos = new ArrayList<>();
            for (Long orderId : successId) {
                OperateRecordDo operateRecordDo = new OperateRecordDo(orderId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkShip_Manual,
                        userId, new Date(), "");
                operateRecordDos.add(operateRecordDo);
            }
            if (!operateRecordDos.isEmpty()) {
                List<List<OperateRecordDo>> partition = ListUtil.partition(operateRecordDos, 3000);
                for (List<OperateRecordDo> partList : partition) {
                    rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
                }
            }
        }

        return errorResList;
    }


    @Override
    public void updateToCancel(MakeShipReq req, Long userId, Long companyId) {
        if (req.getIds().isEmpty()) {
            return;
        }
        List<PlatformOrderDo> orderDos = dao.selectList(new LambdaQueryWrapper<PlatformOrderDo>().in(PlatformOrderDo::getId, req.getIds())
                .eq(PlatformOrderDo::getCompanyId, companyId)
                .in(PlatformOrderDo::getStatus, Arrays.asList(StaticDict.Platform_Order_Status.Zero.getValue(),
                        StaticDict.Platform_Order_Status.One.getValue(),
                        StaticDict.Platform_Order_Status.Five.getValue()
                )));
        if (orderDos.isEmpty()) {
            return;
        }
        this.updateWraCancel(orderDos.stream().map(PlatformOrderDo::getId).collect(Collectors.toList()), userId);
    }


    /**
     * 匹配系统sku
     */
    @Override
    public void matchSystemSku(List<PlatformOrderProductDo> platItems, Long storeId, Long companyId, Long tenantId) {
        if (platItems.isEmpty()) {
            return;
        }
        List<String> platformSkus = platItems.stream().filter(i -> StringUtils.isNotBlank(i.getPlatformSku()) && i.getProductId() == null).map(PlatformOrderProductDo::getPlatformSku).collect(Collectors.toList());
        if (platformSkus.isEmpty()) {
            return;
        }

        Map<String, List<ProductSysDto>> sysSkuMap = platformProductService.getSystemSkuList(platformSkus, storeId)
                .stream().collect(Collectors.groupingBy(ProductSysDto::getPlatformSku));
        if (!sysSkuMap.isEmpty()) {
            platformSkus.removeAll(sysSkuMap.keySet());
        }
        Map<String, Long> skuMap = new HashMap<>();
        if (!platformSkus.isEmpty()) {
            //匹配本地产品表
            skuMap = productDao.getProductsBySku(platformSkus, companyId).stream().collect(Collectors.toMap(ProductSkuVo::getSku, ProductSkuVo::getId));
        }
        List<PlatformOrderProductDo> systemProductList = new ArrayList<>();
        for (PlatformOrderProductDo platItem : platItems) {
            if (StringUtils.isBlank(platItem.getPlatformSku()) || platItem.getSkuType() == 0) {
                continue;
            }
            if (platItem.getProductId() != null) {
                continue;
            }
            List<ProductSysDto> sysSkuList = sysSkuMap.get(platItem.getPlatformSku());
//            if (sysSkuList == null || sysSkuList.isEmpty()) {
//                continue;
//            }
            if (sysSkuList != null && !sysSkuList.isEmpty()) {
                platItem.setSku(sysSkuList.get(0).getSku());
                platItem.setProductId(sysSkuList.get(0).getSystemProductId());
                platItem.setQty(sysSkuList.get(0).getQty() * platItem.getPlatformQty());
                for (int i = 1; i < sysSkuList.size(); i++) {
                    PlatformOrderProductDo sysPlatItem = new PlatformOrderProductDo();
                    sysPlatItem.setOrderId(platItem.getOrderId());
                    sysPlatItem.setPlatformOrderNo(platItem.getPlatformOrderNo());
                    sysPlatItem.setSkuType(0);
                    sysPlatItem.setSku(sysSkuList.get(i).getSku());
                    sysPlatItem.setProductId(sysSkuList.get(i).getSystemProductId());
                    sysPlatItem.setQty(sysSkuList.get(i).getQty() * platItem.getPlatformQty());
                    systemProductList.add(sysPlatItem);
                }
                continue;
            }
            if (skuMap.get(platItem.getPlatformSku()) == null) {
                continue;
            }
            //先不走映射
            platItem.setSku(platItem.getPlatformSku());
            platItem.setProductId(skuMap.get(platItem.getPlatformSku()));
            platItem.setQty(platItem.getPlatformQty());

            //添加到本地
            PlatformAddReq addReq = new PlatformAddReq(storeId, platItem.getPlatformParentSku(), platItem.getPlatformSku());
            List<SkuAddReq> systemSkus = new ArrayList<>();
            systemSkus.add(new SkuAddReq(platItem.getPlatformSku(), 1));
            addReq.setSystemSkus(systemSkus);
            String msg = platformProductService.addNoEx(addReq, null, companyId, tenantId);
        }
        if (!systemProductList.isEmpty()) {
            platItems.addAll(systemProductList);
        }
    }

    /**
     * 配置是否 审核成功自动提交仓库
     */
    @Override
    public Integer ableAutoASubmit(Integer autoSubmit, Long company) {
        redisTemplate.opsForValue().set(RedisKeyConstants.Oms_PlatformOrder_AutoSubmit_ + company, autoSubmit == null ? 1 : autoSubmit);
        return autoSubmit;
    }


    /**
     * 自动审单
     */
    @Override
    public void autoCheck(String autoType) {
        //3-4点不z执行
        LocalTime now = LocalTime.now();
        int hour = now.getHour();
        // 判断当前时间是否在3-4点之间
        if (hour == 3 || hour == 4) {
            System.out.println("当前时间在3-4点之间，不执行任务");
            return;
        }

        if (!StaticDict.Company_Type.Labella.getValue().equals(customer) && !StaticDict.Company_Type.Lemooli.getValue().equals(customer)) {
            return;
        }

        Map<String, Object> companyParam = new HashMap<>();
        List<CompanyPageVo> listNoPower = companyService.getListNoPower(companyParam);
        Map<String, Object> map = new HashMap<>();
        map.put("payStatus", 1);// 已付款的订单
        //自动审单 包含 预约单到时间 的订单 也要自动审核
        if (StringUtils.isNotBlank(autoType)) {
            //1只审核 未审核过的订单  0 只审核 审核过的订单
            map.put("autoType", autoType);
        }
        map.put("action", "autoCheck");
        map.put("dateColumn", "pay_time");
        map.put("beginTime", DateUtil.format(DateUtil.offsetDay(new Date(), -30), DatePattern.NORM_DATE_PATTERN));
        map.put("endTime", DateUtil.format(DateUtil.offsetDay(new Date(), 1), DatePattern.NORM_DATE_PATTERN));
        for (CompanyPageVo companyPageVo : listNoPower) {
            List<Long> range = this.getAutoCheckStoreList(companyPageVo.getId());
            if (range.isEmpty()) {
                continue;
            }
            map.put("storeId", range);//目前只开放 乐天6号店
            map.put("companyId", companyPageVo.getId());
            map.put("tenantId", companyPageVo.getTenantId());
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_Auto_distributeWh, JSON.toJSONString(map));
        }
    }

    @Override
    public void check(Map<String, Object> map, Long userId, Long companyId, Long tenantId) {
        map.put("status", StaticDict.Platform_Order_Status.Zero.getValue());
        map.put("payStatus", 1);// 已付款的订单
        Object distributeWhId = map.get("distributeWhId");
        Object distributeChannelId = map.get("distributeChannelId");
        List<PlatOrderPageRes> list = dao.getList(map);
        if (list.isEmpty()) {
            return;
        }
        //根据platformOrderNo单号去重
        list = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(PlatOrderPageRes::getPlatformOrderNo))), ArrayList::new));
        Object autoType = map.get("autoType");
        Map<String, List<PlatOrderPageRes>> groupedOrders = new HashMap<>();
        for (PlatOrderPageRes order : list) {
            //只审核 未审核过的订单
            if (autoType != null && autoType.equals("1") && StringUtils.isNotBlank(order.getAuditCause())) {
                continue;
            }
            //只审核 审核过的订单
            if (autoType != null && autoType.equals("0") && StringUtils.isBlank(order.getAuditCause())) {
                continue;
            }
            String customerName = order.getStoreId() + "_" + order.getBuyerName() + "_" + order.getCityCode() + "_" + order.getDistrict() + "_" + order.getPostcode() + "_" + order.getDeliveryDate();
            groupedOrders.computeIfAbsent(customerName, k -> new ArrayList<>()).add(order);
        }
        Set<String> platformOrderNoList = new HashSet<>();
        // 存储有重复客户名称的订单集合
        List<List<PlatOrderPageRes>> repeatedCustomerOrders = new ArrayList<>();
        // 存储没有重复客户名称的订单集合
        List<PlatOrderPageRes> nonRepeatedCustomerOrders = new ArrayList<>();
        for (List<PlatOrderPageRes> customerOrders : groupedOrders.values()) {
            if (customerOrders.size() > 1) {
                repeatedCustomerOrders.add(customerOrders);
            } else {
                nonRepeatedCustomerOrders.add(customerOrders.get(0));
            }
            platformOrderNoList.add(StringUtils.join(customerOrders.stream().map(PlatOrderPageRes::getPlatformOrderNo).collect(Collectors.toList()), ","));
        }
        //验证单号重复问题
        Map<String, Long> outBoundMap = new HashMap<>();
        if (!platformOrderNoList.isEmpty()) {
            outBoundMap = orderOutboundDao.selectList(new LambdaQueryWrapper<OrderOutboundDo>()
                    .select(OrderOutboundDo::getPlatformOrderNo, OrderOutboundDo::getId)
                    .eq(OrderOutboundDo::getCompanyId, companyId)
                    .eq(OrderOutboundDo::getOrderOrigin, OutboundOriginEnum.three.getValue())
                    .ge(OrderOutboundDo::getCreateTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -7)))
                    .in(OrderOutboundDo::getPlatformOrderNo, platformOrderNoList)).stream().collect(Collectors.toMap(OrderOutboundDo::getPlatformOrderNo, OrderOutboundDo::getId, (k1, k2) -> k1));
        }
        repeatedCustomerOrders.sort(Comparator.comparing(i -> i.get(0).getPayTime(), Comparator.nullsLast(Date::compareTo)));
        Map<String, List<Long>> failMap = new HashMap<>();
        //需要合并的
        for (List<PlatOrderPageRes> repeatedOrderList : repeatedCustomerOrders) {
            //多个订单的子表
            String megerOrderNo = (StringUtils.join(repeatedOrderList.stream().map(PlatOrderPageRes::getPlatformOrderNo).collect(Collectors.toList()), ","));
            List<Long> orderIds = repeatedOrderList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList());
            if (outBoundMap.containsKey(megerOrderNo)) {
                String failKey = StaticDict.PlatformOrder_Audit_Code.OrderNo_Repeat.getValue() + "________" + "平台单号重复(合并订单)";
                failMap.computeIfAbsent(failKey, k -> new ArrayList<>()).addAll(orderIds);
                continue;
            }
            //判断指定配达日期 有没有超过7天
            boolean deliveryDateOver7Days = false;
            String deliveryDate = "";
            for (PlatOrderPageRes entity : repeatedOrderList) {
                if (StringUtils.isNotBlank(entity.getDeliveryDate())) {
                    try {
                        Date deliverDate = DateUtil.parse(entity.getDeliveryDate(), "yyyy-MM-dd");
                        if (DateUtil.offsetDay(deliverDate, -7).isAfter(new Date())) {
                            deliveryDateOver7Days = true;
                            deliveryDate = entity.getDeliveryDate();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            if (deliveryDateOver7Days) {
                String failKey = StaticDict.PlatformOrder_Audit_Code.OTHER.getValue() + "________" + "指定配达日期:" + deliveryDate + " 超过7天(合并订单)";
                failMap.computeIfAbsent(failKey, k -> new ArrayList<>()).addAll(orderIds);
                continue;
            }

            List<PlatformOrderProductDo> productList = platformOrderProductService.list(new LambdaQueryWrapper<PlatformOrderProductDo>()
                    .in(PlatformOrderProductDo::getOrderId, repeatedOrderList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList())));
            PlatformOrderDo orderDo = BeanConvert.INSTANCE.platformOrderDo(repeatedOrderList.get(0));
            //判断有没有次日达订单 如果有，合并后的订单也是次日达订单
            Integer reserverFlag = repeatedOrderList.stream().filter(i -> i.getReserveFlag() != null && i.getReserveFlag() == 2).findFirst().map(PlatOrderPageRes::getReserveFlag).orElse(null);
            if (reserverFlag != null && reserverFlag == 2) {
                orderDo.setReserveFlag(2);
            }
            if (distributeWhId != null) {
                orderDo.setSendWhId(Long.parseLong(distributeWhId.toString()));
            }
            if (distributeChannelId != null) {
                orderDo.setChannelId(Long.parseLong(distributeChannelId.toString()));
            }
            PlatformOrderCheckReq orderCheckReq = new PlatformOrderCheckReq(orderDo, productList, true, true, megerOrderNo, orderIds, userId, companyId, tenantId);
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_distributeWh, JSON.toJSONString(orderCheckReq));
        }

        nonRepeatedCustomerOrders.sort(Comparator.comparing(PlatOrderPageRes::getPayTime, Comparator.nullsLast(Date::compareTo)));
        List<List<PlatOrderPageRes>> partition = ListUtil.partition(nonRepeatedCustomerOrders, 3000);
        for (List<PlatOrderPageRes> partList : partition) {
            //获取子表
            Map<Long, List<PlatformOrderProductDo>> orderProductMap = platformOrderProductService.list(new LambdaQueryWrapper<PlatformOrderProductDo>()
                            .in(PlatformOrderProductDo::getOrderId, partList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList()))).stream()
                    .collect(Collectors.groupingBy(PlatformOrderProductDo::getOrderId));
            for (PlatOrderPageRes orderPageRes : partList) {
                if (outBoundMap.containsKey(orderPageRes.getPlatformOrderNo())) {
                    String failKey = StaticDict.PlatformOrder_Audit_Code.OrderNo_Repeat.getValue() + "________" + "平台单号重复";
                    failMap.computeIfAbsent(failKey, k -> new ArrayList<>()).add(orderPageRes.getId());
                    continue;
                }
                PlatformOrderDo orderDo = dao.selectById(orderPageRes.getId());
                if (orderDo == null) {
                    continue;
                }
                if ((StaticDict.Company_Type.Labella.getValue().equals(customer) || StaticDict.Company_Type.Lemooli.getValue().equals(customer)) && distributeWhId != null) {
                    if (StringUtils.isNotBlank(orderDo.getDeliveryDate())) {
                        try {
                            Date deliverDate = DateUtil.parse(orderDo.getDeliveryDate(), "yyyy-MM-dd");
                            if (DateUtil.offsetDay(deliverDate, -7).isAfter(new Date())) {
                                String failKey = StaticDict.PlatformOrder_Audit_Code.OTHER.getValue() + "________" + "指定配达日期:" + orderDo.getDeliveryDate() + " 超过7天";
                                failMap.computeIfAbsent(failKey, k -> new ArrayList<>()).add(orderDo.getId());
                                continue;
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                if (distributeWhId != null) {
                    orderDo.setSendWhId(Long.parseLong(distributeWhId.toString()));
                }
                if (distributeChannelId != null) {
                    orderDo.setChannelId(Long.parseLong(distributeChannelId.toString()));
                }
                PlatformOrderCheckReq orderCheckReq = new PlatformOrderCheckReq(orderDo, orderProductMap.get(orderDo.getId()), true, false, null, null, userId, companyId, tenantId);
                rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_distributeWh, JSON.toJSONString(orderCheckReq));
            }
        }
        for (String reason : failMap.keySet()) {
            if (CollUtil.isEmpty(failMap.get(reason))) {
                continue;
            }
            //将  failMap.values() 转成集合
            List<Long> failOrderIds = failMap.get(reason).stream().distinct().collect(Collectors.toList());
            String[] split = reason.split("________");
            LambdaUpdateWrapper<PlatformOrderDo> updateWrapper = new LambdaUpdateWrapper<PlatformOrderDo>();
            updateWrapper.set(PlatformOrderDo::getAuditCode, split[0]);
            updateWrapper.set(PlatformOrderDo::getAuditCause, split[1]);
            updateWrapper.set(PlatformOrderDo::getSendWhId, null);
            updateWrapper.set(PlatformOrderDo::getChannelId, null);
            updateWrapper.in(PlatformOrderDo::getId, failOrderIds);
            this.update(updateWrapper);
        }
    }


    /**
     * 分配仓库和物流
     */
    @Override
    public void distributeWh(Map<String, Object> map, Long userId, Long companyId, Long tenantId) {
        map.put("status", StaticDict.Platform_Order_Status.Zero.getValue());
        Object distributeWhId = map.get("distributeWhId");
        Object distributeChannelId = map.get("distributeChannelId");
        if (distributeWhId == null || distributeChannelId == null) {
            return;
        }
        this.check(map, userId, companyId, tenantId);
    }


    /**
     * 自动标发
     */
    @Override
    public void autoMarkShip() {
        if (!StaticDict.Company_Type.Labella.getValue().equals(customer) && !StaticDict.Company_Type.Lemooli.getValue().equals(customer)) {
            return;
        }
        Map<String, Object> companyParam = new HashMap<>();
        List<CompanyPageVo> listNoPower = companyService.getListNoPower(companyParam);
        Map<String, Object> map = new HashMap<>();
        map.put("payStatus", 1);// 已付款的订单
        map.put("dateColumn", "ship_time");
        map.put("beginTime", DateUtil.format(DateUtil.offsetDay(new Date(), -10), DatePattern.NORM_DATE_PATTERN));
        map.put("endTime", DateUtil.format(DateUtil.offsetDay(new Date(), 1), DatePattern.NORM_DATE_PATTERN));
        for (CompanyPageVo companyPageVo : listNoPower) {
            List<Long> range = this.getAutoCheckStoreList(companyPageVo.getId());
            if (range.isEmpty()) {
                continue;
            }
            map.put("storeId", range);//目前只开放 乐天6号店
            map.put("companyId", companyPageVo.getId());
            map.put("tenantId", companyPageVo.getTenantId());
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_Auto_MarkShip, JSON.toJSONString(map));
        }
    }

    /**
     * 标发
     */
    @Override
    public void markShip(Map<String, Object> map, String type, Long userId, Long companyId, Long tenantId) {
        map.put("status", StaticDict.Platform_Order_Status.Three.getValue());
        if ("auto".equals(type)) {
            map.put("neMarkShipmentStatus", 3);
        }
        else {
            map.put("neMarkShipmentStatus", 1);
        }
        List<PlatOrderPageRes> orderDos = dao.getList(map);
        List<Long> failId = orderDos.stream().filter(i -> StringUtils.isBlank(i.getTrackNo()) || StringUtils.isBlank(i.getLogisticsCarrier())).map(PlatOrderPageRes::getId).collect(Collectors.toList());
        this.updateMarkStatus(failId, 2, "无物流跟踪号或无承运商");

        Map<String, List<PlatOrderPageRes>> orderMap = orderDos.stream()
                .filter(i -> (!StringUtils.isBlank(i.getTrackNo()) || StringUtils.isBlank(i.getLogisticsCarrier())))
                .collect(Collectors.groupingBy(i -> i.getPlatformCode() + "____" + i.getStoreId()));

        for (String key : orderMap.keySet()) {
            String platformCode = key.split("____")[0];
            Long storeId = Long.parseLong(key.split("____")[1]);
            List<PlatOrderPageRes> platOrderList = orderMap.get(key);
            //获取物流渠道
            Map<Long, String> channelMap = logisticsChannelService.getChannelMap(tenantId);
            if (StaticDict.Store_PlatformCode.Qoo10.getValue().equals(platformCode)) {
                List<Long> fail = new ArrayList<>();
                Map<Long, List<PlatformOrderTrackDo>> trackMap = platformOrderTrackDao.selectList(new LambdaQueryWrapper<PlatformOrderTrackDo>()
                                .in(PlatformOrderTrackDo::getOrderId, platOrderList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList())))
                        .stream().collect(Collectors.groupingBy(PlatformOrderTrackDo::getOrderId));
                List<Qoo10RequestReq> markList = new ArrayList<>();
                for (PlatOrderPageRes orderDo : platOrderList) {
                    if (trackMap.get(orderDo.getId()) == null) {
                        fail.add(orderDo.getId());
                        continue;
                    }
                    Map<String, List<PlatformOrderTrackDo>> collect = trackMap.get(orderDo.getId()).stream().collect(Collectors.groupingBy(PlatformOrderTrackDo::getCarrier));
                    for (String carrier : collect.keySet()) {//qoo10 默认传一个
                        List<String> trackNos = collect.get(carrier).stream().map(PlatformOrderTrackDo::getTrackNumber).collect(Collectors.toList());
                        if (trackNos.isEmpty()) {
                            continue;
                        }
                        Long channelId = collect.get(carrier).get(0).getChannelId();
                        markList.add(new Qoo10RequestReq(orderDo.getId(), orderDo.getPlatformOrderNo(), carrier, trackNos.get(0), channelMap.get(channelId), orderDo.getBasketId()));
                        break;
                    }
                }
                //异步去坐
                rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Qoo10_MarkShip, JSON.toJSONString(new Qoo10MarkShipConsumerReq(storeId, markList, userId)));
                if (!fail.isEmpty()) {
                    this.updateMarkStatus(fail, 2, "无单号");
                }
            } else if (StaticDict.Store_PlatformCode.Rakuten.getValue().equals(platformCode)) {
                //乐天标发
                List<RakutenOrderShippingModelRequest> markList = new ArrayList<>();
                List<Long> fail = new ArrayList<>();
                Map<String, Long> idMap = new HashMap<>();
                Map<Long, String> trackNap = new HashMap<>();
                //获取快递单号信息
                Map<Long, List<PlatformOrderTrackDo>> trackMap = platformOrderTrackDao.selectList(new LambdaQueryWrapper<PlatformOrderTrackDo>()
                                .in(PlatformOrderTrackDo::getOrderId, platOrderList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList())))
                        .stream().collect(Collectors.groupingBy(PlatformOrderTrackDo::getOrderId));
                //拆单的单独去标发
                List<List<RakutenOrderShippingModelRequest>> singleMarkList = new ArrayList<>();
                Set<String> existSplitOrderNumbers = new HashSet<>();
                for (PlatOrderPageRes orderDo : platOrderList) {
                    if (StringUtils.isBlank(orderDo.getBasketId())) {
                        fail.add(orderDo.getId());
                        continue;
                    }
                    if (trackMap.get(orderDo.getId()) == null) {
                        fail.add(orderDo.getId());
                        continue;
                    }
                    //快递公司 编号
                    List<ShippingModelEntity> shippingModelEntities = new ArrayList<>();
                    StringBuilder track = new StringBuilder();
                    for (PlatformOrderTrackDo platformOrderTrackDo : trackMap.get(orderDo.getId())) {
                        String deliveryCompany = getDeliveryCompany(platformOrderTrackDo.getCarrier());
                        ShippingModelEntity shipping = new ShippingModelEntity(deliveryCompany, platformOrderTrackDo.getTrackNumber().replaceAll("-", "").trim(),
                                DateUtils.dateFormatToString(orderDo.getShipTime() == null ? new Date() : orderDo.getShipTime()));
                        shippingModelEntities.add(shipping);
                        if (track.length() > 0) {
                            track.append(",");
                        }
                        track.append(platformOrderTrackDo.getTrackNumber());
                    }
                    BasketidModelRequest basket = new BasketidModelRequest(Long.parseLong(orderDo.getBasketId()), shippingModelEntities);
                    //判断单号是不是以 -1 -2 -3 结尾
                    boolean split = false;
                    if (orderDo.getPlatformOrderNo().endsWith("-1") || orderDo.getPlatformOrderNo().endsWith("-2") || orderDo.getPlatformOrderNo().endsWith("-3")
                            || orderDo.getPlatformOrderNo().endsWith("-4") || orderDo.getPlatformOrderNo().endsWith("-5") || orderDo.getPlatformOrderNo().endsWith("-6")) {
                        orderDo.setPlatformOrderNo(orderDo.getPlatformOrderNo().substring(0, orderDo.getPlatformOrderNo().length() - 2));
                        split = true;
                    }
                    RakutenOrderShippingModelRequest model = new RakutenOrderShippingModelRequest(orderDo.getPlatformOrderNo(), Collections.singletonList(basket));
                    idMap.put(orderDo.getPlatformOrderNo() + "_" + orderDo.getBasketId(), orderDo.getId());
                    trackNap.put(orderDo.getId(), track.toString());
                    if (split) {
                        if (existSplitOrderNumbers.contains(orderDo.getPlatformOrderNo())) {
                            continue;
                        }
                        singleMarkList.add(Collections.singletonList(model));
                        existSplitOrderNumbers.add(orderDo.getPlatformOrderNo());
                    } else {
                        markList.add(model);
                    }
                }
                List<List<RakutenOrderShippingModelRequest>> partition = ListUtil.partition(markList, 100);
//                partition.addAll(singleMarkList); //java.lang.UnsupportedOperationException
                for (List<RakutenOrderShippingModelRequest> mark : partition) {
                    Map<String, Long> partitionIdMap = new HashMap<>();
                    Map<Long, String> partitionTrackNap = new HashMap<>();
                    for (RakutenOrderShippingModelRequest model : mark) {
                        String idMapKey = model.getOrderNumber() + "_" + model.getBasketidModelList().get(0).getBasketId();
                        Long orderId = idMap.get(idMapKey);
                        if (orderId == null) {
                            continue;
                        }
                        partitionIdMap.put(idMapKey , orderId);
                        partitionTrackNap.put(orderId, trackNap.get(orderId));
                    }
                    rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Rakuten_MarkShip, JSON.toJSONString(new RakutenMarkShipConsumerReq(storeId, mark, userId, companyId, partitionIdMap, partitionTrackNap)));
                }
                //拆单的按照单号去重， 不要一次性全部标发 会失败的
                for (List<RakutenOrderShippingModelRequest> mark : singleMarkList) {
                    Map<String, Long> partitionIdMap = new HashMap<>();
                    Map<Long, String> partitionTrackNap = new HashMap<>();
                    for (RakutenOrderShippingModelRequest model : mark) {
                        String idMapKey = model.getOrderNumber() + "_" + model.getBasketidModelList().get(0).getBasketId();
                        Long orderId = idMap.get(idMapKey);
                        if (orderId == null) {
                            continue;
                        }
                        partitionIdMap.put(idMapKey , orderId);
                        partitionTrackNap.put(orderId, trackNap.get(orderId));
                    }
                    rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Rakuten_MarkShip, JSON.toJSONString(new RakutenMarkShipConsumerReq(storeId, mark, userId, companyId, partitionIdMap, partitionTrackNap)));
                }
                if (!fail.isEmpty()) {
                    this.updateMarkStatus(fail, 2, "无包裹id或无单号");
                }

            } else if (StaticDict.Store_PlatformCode.Shopify.getValue().equals(platformCode)) {
                List<Long> fail = new ArrayList<>();
                for (PlatOrderPageRes orderDo : platOrderList) {
                    if (StringUtils.isBlank(orderDo.getBasketId())) {
                        fail.add(orderDo.getId());
                        continue;
                    }
                    rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Shopify_MarkShip, orderDo.getId());
                }
                if (!fail.isEmpty()) {
                    this.updateMarkStatus(fail, 2, "无包裹id");
                }
            } else if (StaticDict.Store_PlatformCode.Amazon.getValue().equals(platformCode)) {
                List<List<PlatOrderPageRes>> partition = ListUtil.partition(platOrderList, 5000);
                List<Long> fail = new ArrayList<>();
                for (List<PlatOrderPageRes> partitionList : partition) {
                    List<AmazonOrderFulfillmentEt> marks = new ArrayList<>();
                    //平台订单子表信息
                    Map<Long, List<PlatformOrderProductDo>> productMap = platformOrderProductService.list(new LambdaQueryWrapper<PlatformOrderProductDo>()
                                    .in(PlatformOrderProductDo::getOrderId, partitionList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList())))
                            .stream().collect(Collectors.groupingBy(PlatformOrderProductDo::getOrderId));
                    //获取快递单号信息
                    Map<Long, List<PlatformOrderTrackDo>> trackMap = platformOrderTrackDao.selectList(new LambdaQueryWrapper<PlatformOrderTrackDo>()
                                    .in(PlatformOrderTrackDo::getOrderId, partitionList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList())))
                            .stream().collect(Collectors.groupingBy(PlatformOrderTrackDo::getOrderId));
                    //拆单需要 匹配sku
                    for (PlatOrderPageRes platOrderPageRes : partitionList) {
                        List<PlatformOrderProductDo> productDos = productMap.get(platOrderPageRes.getId());
                        if (productDos == null || productDos.isEmpty()) {
                            fail.add(platOrderPageRes.getId());
                            continue;
                        }
                        List<PlatformOrderTrackDo> trackDos = trackMap.get(platOrderPageRes.getId());
                        if (trackDos == null || trackDos.isEmpty()) {
                            fail.add(platOrderPageRes.getId());//todo 改成Map<String, List<Long>>
                            continue;
                        }
                        List<PlatformOrderProductDo> platProductList = productDos.stream().filter(i -> i.getSkuType() == 1).collect(Collectors.toList());
                        int sum = platProductList.stream().mapToInt(PlatformOrderProductDo::getPlatformQty).sum();
                        int minSize = Math.min(trackDos.size(), sum);
                        for (int i = 0; i < minSize; i++) {
                            PlatformOrderTrackDo trackDo = trackDos.get(i);
                            String carrier = trackDo.getCarrier();
                            String deliveryCompany = this.getAmazonDeliverCompany(carrier);
                            AmazonOrderFulfillmentEt fulfillment = new AmazonOrderFulfillmentEt();
                            fulfillment.setId(trackDo.getOrderId());
                            fulfillment.setAmazonOrderID(platOrderPageRes.getPlatformOrderNo());
                            fulfillment.setFulfillmentDate(TimeUtils.formatDate(platOrderPageRes.getShipTime(), "yyyy-MM-dd HH:mm:ss.SSS").replace(" ", "T") + "+09:00");

                            AmazonOrderFulfillment.FulfillmentData fulfillmentData = new AmazonOrderFulfillment.FulfillmentData();
                            fulfillmentData.setCarrierCode(deliveryCompany);
                            if (StringUtils.isNotBlank(deliveryCompany)) {
                                String channelCode = channelMap.get(trackDo.getChannelId());
                                if ("yamato_zhai".equals(channelCode)) {//黑猫宅急便
                                    fulfillmentData.setShippingMethod("TA-Q-BIN");
                                } else if ("yamato_one".equals(channelCode) || "yamato_more".equals(channelCode)) {
                                    fulfillmentData.setShippingMethod("Nekopos");
                                }
                            }
                            fulfillmentData.setShipperTrackingNumber(trackDo.getTrackNumber().replaceAll("-", "").trim());
                            fulfillment.setFulfillmentData(fulfillmentData);
                            List<AmazonOrderFulfillment.Item> items = new ArrayList<>();
                            if (i == minSize - 1) {
                                //最后一个
                                for (PlatformOrderProductDo productDo : platProductList) {
                                    if (productDo.getPlatformQty() == 0) {
                                        continue;
                                    }
                                    AmazonOrderFulfillment.Item itemData = new AmazonOrderFulfillment.Item();
                                    itemData.setAmazonOrderItemCode(productDo.getItemId());
                                    itemData.setMerchantFulfillmentItemID(String.valueOf(i + 1));
                                    itemData.setQuantity(String.valueOf(productDo.getPlatformQty()));//要减去已发货数量
                                    items.add(itemData);
                                }
                            } else {
                                for (PlatformOrderProductDo productDo : platProductList) {
                                    if (productDo.getPlatformQty() == 0) {
                                        continue;
                                    }
                                    AmazonOrderFulfillment.Item itemData = new AmazonOrderFulfillment.Item();
                                    itemData.setAmazonOrderItemCode(productDo.getItemId());
                                    itemData.setMerchantFulfillmentItemID(String.valueOf(i + 1));
                                    itemData.setQuantity(1 + "");//要减去已发货数量
                                    items.add(itemData);
                                    productDo.setPlatformQty(productDo.getPlatformQty() - 1);
                                    break;
                                }
                            }

                            fulfillment.setItem(items);
                            marks.add(fulfillment);
                        }
                    }
                    rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Amazon_MarkShip, JSON.toJSONString(new AmazonMarkShipConsumerReq(marks, userId, storeId)));

                }
                this.updateMarkStatus(fail, 2, "无产品信息或无单号");

            } else if (StaticDict.Store_PlatformCode.Yahoo.getValue().equals(platformCode)) {
                List<YahooMarkShipReq> markList = new ArrayList<>();
                Map<Long, List<PlatformOrderTrackDo>> trackMap = platformOrderTrackDao.selectList(new LambdaQueryWrapper<PlatformOrderTrackDo>()
                                .in(PlatformOrderTrackDo::getOrderId, platOrderList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList())))
                        .stream().collect(Collectors.groupingBy(PlatformOrderTrackDo::getOrderId));
                for (PlatOrderPageRes orderDo : platOrderList) {
                    Map<String, List<PlatformOrderTrackDo>> collect = trackMap.get(orderDo.getId()).stream().collect(Collectors.groupingBy(PlatformOrderTrackDo::getCarrier));
                    for (String carrier : collect.keySet()) {
                        List<String> trackNos = collect.get(carrier).stream().map(PlatformOrderTrackDo::getTrackNumber).collect(Collectors.toList());
                        markList.add(new YahooMarkShipReq(orderDo.getId(), StringUtils.join(trackNos, ","), this.getDeliveryCompany(carrier), orderDo.getPlatformOrderNo(), orderDo.getShipTime()));
                        break;
                    }
                }
                rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Yahoo_MarkShip, JSON.toJSONString(new YahooMarkShipConsumerReq(markList, userId, storeId)));
            } else if (StaticDict.Store_PlatformCode.Wowma.getValue().equals(platformCode)) {
                List<WowmaMarkShipReq> markList = new ArrayList<>();
                Map<Long, List<PlatformOrderTrackDo>> trackMap = platformOrderTrackDao.selectList(new LambdaQueryWrapper<PlatformOrderTrackDo>()
                                .in(PlatformOrderTrackDo::getOrderId, platOrderList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList())))
                        .stream().collect(Collectors.groupingBy(PlatformOrderTrackDo::getOrderId));
                for (PlatOrderPageRes orderDo : platOrderList) {
                    List<String> trackNos = trackMap.get(orderDo.getId()).stream().map(PlatformOrderTrackDo::getTrackNumber).collect(Collectors.toList());
                    String carrier = trackMap.get(orderDo.getId()).get(0).getCarrier();
                    markList.add(new WowmaMarkShipReq(orderDo.getId(), trackNos.get(0), this.getWowmaDeliveryCompany(carrier), orderDo.getPlatformOrderNo(), orderDo.getShipTime()));
                }
                rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Wowma_MarkShip, JSON.toJSONString(new WowmaMarkShipConsumerReq(markList, userId, storeId)));

            } else {
                //makeShop 平台标发
                Map<Long, List<PlatformOrderTrackDo>> trackMap = platformOrderTrackDao.selectList(new LambdaQueryWrapper<PlatformOrderTrackDo>()
                                .in(PlatformOrderTrackDo::getOrderId, platOrderList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList())))
                        .stream().collect(Collectors.groupingBy(PlatformOrderTrackDo::getOrderId));
                List<UpdateOrderAttribute> updateOrderAttributeList = new ArrayList<>();
                for (PlatOrderPageRes orderDo : platOrderList) {
                    List<String> trackNos = trackMap.get(orderDo.getId()).stream().map(PlatformOrderTrackDo::getTrackNumber).collect(Collectors.toList());
                    String carrier = trackMap.get(orderDo.getId()).get(0).getCarrier();
                    UpdateOrderAttribute updateOrderAttribute = new UpdateOrderAttribute();
                    updateOrderAttribute.setDisplayOrderNumber(orderDo.getPlatformOrderNo());
                    DeliveryRequestInfoForUpdate deliveryRequestInfo = new DeliveryRequestInfoForUpdate();
                    deliveryRequestInfo.setDeliveryId(orderDo.getBasketId());
//                    deliveryRequestInfo.setSlipNumber(orderDo.getTrackNo());
                    //TODO 目前暂定标发一个单号
                    deliveryRequestInfo.setSlipNumber(trackNos.get(0).replaceAll("-", "").trim());
                    deliveryRequestInfo.setDeliveryCompanyCode(this.getMakeShopDeliveryCompany(carrier));
                    if (orderDo.getShipTime() != null) {
                        deliveryRequestInfo.setEstimatedShippingDate(DateUtils.dateFormatToString(orderDo.getShipTime(), "yyyy-MM-dd"));
                    } else {
                        deliveryRequestInfo.setEstimatedShippingDate(DateUtils.dateFormatToString(new Date(), "yyyy-MM-dd"));
                    }
                    if (StrUtil.isNotBlank(orderDo.getDeliveryDate())) {
                        if (DateUtils.regexCheckDate1(orderDo.getDeliveryDate())) {
                            deliveryRequestInfo.setDesiredDeliveryDate(orderDo.getDeliveryDate());
                        } else if (DateUtils.regexCheckDate2(orderDo.getDeliveryDate())) {
                            deliveryRequestInfo.setDesiredDeliveryDate(orderDo.getDeliveryDate().replaceAll("/", "-"));
                        }
                    }
                    if (StrUtil.isNotBlank(orderDo.getDeliveryTimeName())) {
                        deliveryRequestInfo.setDesiredDeliveryTimezone(orderDo.getDeliveryTimeName());
                    }
                    updateOrderAttribute.setDeliveryRequestInfos(Collections.singletonList(deliveryRequestInfo));
                    updateOrderAttributeList.add(updateOrderAttribute);
                }
                rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_MakeShop_MarkShip, JSON.toJSONString(new MakeShopMarkShipConsumerReq(updateOrderAttributeList, storeId, userId)));
            }
        }

    }
    public String getAmazonDeliverCompany(String carrier) {
        String deliveryCompany = "";
        if ("Yamato".equalsIgnoreCase(carrier)) {
            deliveryCompany = "YAMATO TRANSPORT";

        } else if ("Sagawa".equalsIgnoreCase(carrier)) {
            deliveryCompany = "SAGAWA EXPRESS";
        } else if ("Japan Post".equals(carrier) || "日本郵便".equalsIgnoreCase(carrier)) {
            deliveryCompany = "Japan Post";
        } else if ("Seino".equalsIgnoreCase(carrier)) {
            deliveryCompany = "SEINO TRANSPORTATION";
        } else if ("DHL".equalsIgnoreCase(carrier)) {
            deliveryCompany = "DHL";
        } else if ("FedEx".equalsIgnoreCase(carrier)) {
            deliveryCompany = "FedEx";
        } else if ("UPS".equalsIgnoreCase(carrier)) {
            deliveryCompany = "UPS";
        } else if ("USPS".equalsIgnoreCase(carrier)) {
            deliveryCompany = "USPS";
        } else if ("Yun Express".equals(carrier)) {
            deliveryCompany = "Yun Express";
        }
        return deliveryCompany;
    }


    private String getWowmaDeliveryCompany(String carrier) {
        //"1:クロネコヤマト、2:佐川急便、4:福山通運、
        //5:西濃運輸、6:日本郵便、7:Rakuten EXPRESS、9:その他配送会社"
        String deliveryCompany = "9";
        if ("Yamato".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1";
        } else if ("Sagawa".equalsIgnoreCase(carrier)) {
            deliveryCompany = "2";
        } else if ("Japan Post".equalsIgnoreCase(carrier)) {
            deliveryCompany = "6";
        } else if ("Seino".equalsIgnoreCase(carrier)) {
            deliveryCompany = "5";
        }
        return deliveryCompany;
    }


    /**
     * 乐天和yahoo 的一样
     *
     * @param carrier
     * @return
     */
    private String getDeliveryCompany(String carrier) {
        String deliveryCompany = "1000";
        if ("Yamato".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1001";
        } else if ("Sagawa".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1002";
        } else if ("Japan Post".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1003";
        } else if ("Seino".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1004";
        } else if ("DHL".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1018";
        } else if ("FedEx".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1019";
        } else if ("UPS".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1020";
        } else if ("USPS".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1024";
        }
        return deliveryCompany;
    }

    private String getMakeShopDeliveryCompany(String carrier) {
        String deliveryCompany = "";
        if ("Yamato".equalsIgnoreCase(carrier)) {
            deliveryCompany = "002";
        } else if ("Sagawa".equalsIgnoreCase(carrier)) {
            deliveryCompany = "003";
        } else if ("Japan Post".equalsIgnoreCase(carrier)) {//todo 日本郵便
            deliveryCompany = "001";
        } else if ("Seino".equalsIgnoreCase(carrier)) {
            deliveryCompany = "006";
        } else if ("DHL".equalsIgnoreCase(carrier)) {
            deliveryCompany = "023";
        }/* else if ("FedEx".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1019";
        } else if ("UPS".equalsIgnoreCase(carrier)) {
            deliveryCompany = "1020";
        }*/ else if ("USPS".equalsIgnoreCase(carrier)) {
            deliveryCompany = "004";
        }
        return deliveryCompany;
    }


    @Override
    public void cancel(PlatOrderCancelConsumerReq req) {
        if (StringUtils.isBlank(req.getPlatformOrderNo())) {
            return;
        }
        if (!req.getPlatformOrderNo().contains(",")) {
            List<PlatformOrderDo> list = dao.selectList(new LambdaQueryWrapper<PlatformOrderDo>()
                    .in(PlatformOrderDo::getStatus, Arrays.asList(StaticDict.Platform_Order_Status.Zero.getValue(),
                            StaticDict.Platform_Order_Status.One.getValue(), StaticDict.Platform_Order_Status.Two.getValue(),
                            StaticDict.Platform_Order_Status.Five.getValue()
                    ))
                    .eq(PlatformOrderDo::getPlatformOrderNo, req.getPlatformOrderNo()));
            List<Long> orderIds = list.stream().map(PlatformOrderDo::getId).collect(Collectors.toList());
            if (!orderIds.isEmpty()) {
                this.updateWraCancel(orderIds, req.getUserId());
                platformOrderTrackDao.delete(new LambdaQueryWrapper<PlatformOrderTrackDo>()
                        .in(PlatformOrderTrackDo::getOrderId, orderIds).eq(PlatformOrderTrackDo::getOutboundId, req.getOutboundId()));
            }
        } else {
            String[] platformOrderArr = req.getPlatformOrderNo().split(",");
            List<Object> platformOrderIds = dao.selectObjs(new LambdaQueryWrapper<PlatformOrderDo>()
                    .select(PlatformOrderDo::getId)
                    .in(PlatformOrderDo::getStatus, Arrays.asList(StaticDict.Platform_Order_Status.Zero.getValue(),
                            StaticDict.Platform_Order_Status.One.getValue(), StaticDict.Platform_Order_Status.Two.getValue(),
                            StaticDict.Platform_Order_Status.Five.getValue()
                    ))
                    .in(PlatformOrderDo::getPlatformOrderNo, Arrays.asList(platformOrderArr))
                    .eq(PlatformOrderDo::getCompanyId, req.getCompanyId())
                    .ge(PlatformOrderDo::getOrderTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -30))));
            if (platformOrderIds.isEmpty()) {
                return;
            }
            platformOrderTrackDao.delete(new LambdaQueryWrapper<PlatformOrderTrackDo>()
                    .eq(PlatformOrderTrackDo::getOutboundId, req.getOutboundId())
                    .in(PlatformOrderTrackDo::getOrderId, platformOrderIds));
            //看看有没有未取消的 一件代发出库
            int count = orderOutboundDao.selectCount(new LambdaQueryWrapper<OrderOutboundDo>().eq(OrderOutboundDo::getPlatformOrderNo, req.getPlatformOrderNo())
                    .eq(OrderOutboundDo::getCompanyId, req.getCompanyId()).eq(OrderOutboundDo::getOrderOrigin, OutboundOriginEnum.three.getValue())
                    .in(OrderOutboundDo::getStatus, NormalOutboundStatusEnum.one.getValue(), NormalOutboundStatusEnum.two.getValue(), NormalOutboundStatusEnum.three.getValue(),
                            NormalOutboundStatusEnum.four.getValue(), NormalOutboundStatusEnum.five.getValue(), NormalOutboundStatusEnum.six.getValue())
                    .ge(OrderOutboundDo::getCreateTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -7))));
            if (count == 0) {
                this.updateWraCancel(platformOrderIds.stream().map(i -> Long.parseLong(i.toString())).collect(Collectors.toList()), req.getUserId());
            }
        }

    }

    @Override
    public void updateWhIdFromOut(List<String> platformOrderNos, Long whId, Long channelId, Long userId, Long companyId) {
        if (platformOrderNos.isEmpty()) {
            return;
        }
        if (whId == null && channelId == null) {
            return;
        }
        LambdaQueryWrapper<PlatformOrderDo> wrapper = new LambdaQueryWrapper<PlatformOrderDo>();
        wrapper.in(PlatformOrderDo::getPlatformOrderNo, platformOrderNos).eq(PlatformOrderDo::getCompanyId, companyId);
        List<PlatformOrderDo> orderDos = dao.selectList(wrapper);
        if (CollUtil.isEmpty(orderDos)) {
            return;
        }
        String whName = "-";
        if (whId != null) {
            WarehouseDo warehouseServiceById = warehouseService.getById(whId);
            if (warehouseServiceById != null) {
                whName = warehouseServiceById.getWhCode();
            }
        }
        String channelName = "-";
        if (channelId != null) {
            LogisticsChannelDo logisticsChannelDo = logisticsChannelService.getById(channelId);
            if (logisticsChannelDo != null) {
                channelName = logisticsChannelDo.getChannelName();
            }
        }
        List<OperateRecordDo> operateRecordDos = new ArrayList<>();

        List<Long> ids = new ArrayList<>();
        for (PlatformOrderDo orderDo : orderDos) {
            if ((whId != null && !Objects.equals(orderDo.getSendWhId(), whId)) || (channelId != null && !Objects.equals(orderDo.getChannelId(), channelId))) {
                ids.add(orderDo.getId());
            }
            else {
                continue;
            }
            String  contentValue = whName + SysConstant.operateRecordSeparator + channelName;
            OperateRecordDo operateRecordDo = new OperateRecordDo(orderDo.getId(), OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_Update_Warehouse,
                    userId, new Date(), contentValue);
            operateRecordDos.add(operateRecordDo);
        }
        if (ids.isEmpty()) {
            return;
        }
        LambdaUpdateWrapper<PlatformOrderDo> updateWrapper = new LambdaUpdateWrapper<PlatformOrderDo>();
        updateWrapper.in(PlatformOrderDo::getId, ids);
        updateWrapper.set(whId != null, PlatformOrderDo::getSendWhId, whId);
        updateWrapper.set(channelId != null, PlatformOrderDo::getChannelId, channelId);
        updateWrapper.set(PlatformOrderDo::getUpdateTime, new Date());
        updateWrapper.set(PlatformOrderDo::getUpdateBy, userId);
        this.update(updateWrapper);

        //操作记录
        if (!operateRecordDos.isEmpty()) {
            List<List<OperateRecordDo>> partition = ListUtil.partition(operateRecordDos, 3000);
            for (List<OperateRecordDo> partList : partition) {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
            }
        }
    }

    public void updateWraCancel(List<Long> ids, Long userId) {
        if (ids.isEmpty()) {
            return;
        }
        LambdaUpdateWrapper<PlatformOrderDo> updateWrapper = new LambdaUpdateWrapper<PlatformOrderDo>();
        updateWrapper.in(PlatformOrderDo::getId, ids);
        updateWrapper.set(PlatformOrderDo::getStatus, StaticDict.Platform_Order_Status.Four.getValue());
        updateWrapper.set(PlatformOrderDo::getCancelWay, 1);
        updateWrapper.set(PlatformOrderDo::getCancelTime, new Date());
        updateWrapper.set(PlatformOrderDo::getCancelBy, userId);
        this.update(updateWrapper);
    }


    @Override
    public void send(PlatOrderSendConsumerReq req) {
        if (req.getOrders().isEmpty()) {
            return;
        }
        //通过平台订单号 获取 平台订单
        for (PlatformOrderTrackNoEntity order : req.getOrders()) {
            if (StringUtils.isBlank(order.getPlatformOrderNo())) {
                continue;
            }
            //还存在未发火的订单。先把这个的单号 传过去。
            String[] platformOrderArr = order.getPlatformOrderNo().split(",");
            List<Object> platformOrderIds = dao.selectObjs(new LambdaQueryWrapper<PlatformOrderDo>()
                    .select(PlatformOrderDo::getId)
                    .in(PlatformOrderDo::getPlatformOrderNo, Arrays.asList(platformOrderArr))
                    .eq(PlatformOrderDo::getCompanyId, req.getCompanyId())
                    .ne( PlatformOrderDo::getStatus, StaticDict.Platform_Order_Status.Three.getValue())
                    .ge(PlatformOrderDo::getOrderTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -30))));
            if (platformOrderIds.isEmpty()) {
                continue;
            }
            List<OrderOutboundPackageDo> packageDoList = orderOutboundPackageDao.selectList(new LambdaQueryWrapper<OrderOutboundPackageDo>()
                    .in(OrderOutboundPackageDo::getOutboundId, order.getOutboundId()));
            String mergeOrderId = platformOrderIds.size() > 1 ? StringUtils.join(platformOrderIds, "_") : null;
            List<PlatformOrderTrackDo> trackDos = new ArrayList<>();
            for (Object platformOrderId : platformOrderIds) {
                for (OrderOutboundPackageDo boundPackageDo : packageDoList) {
                    if (StringUtils.isBlank(boundPackageDo.getTrackingNumber())) {
                        continue;
                    }
                    String[] splitTrackArr = boundPackageDo.getTrackingNumber().split(",");
                    for (String s : splitTrackArr) {
                        trackDos.add(new PlatformOrderTrackDo(mergeOrderId, Long.parseLong(platformOrderId.toString()), order.getOutboundId(),
                                boundPackageDo.getId(), order.getChannelId(), order.getCarrier(), s, req.getUserId()));
                    }
                }
            }
            //批量插入
            if (!trackDos.isEmpty()) {
                platformOrderTrackDao.insertBatch(trackDos);
                //更新主表快递单号
                dao.updateTrackNo(platformOrderIds);
            }
            //先判断是不是都发货了
            int count = orderOutboundDao.selectCount(new LambdaQueryWrapper<OrderOutboundDo>().eq(OrderOutboundDo::getPlatformOrderNo, order.getPlatformOrderNo())
                    .eq(OrderOutboundDo::getCompanyId, req.getCompanyId()).eq(OrderOutboundDo::getOrderOrigin, OutboundOriginEnum.three.getValue())
                    .in(OrderOutboundDo::getStatus, NormalOutboundStatusEnum.one.getValue(), NormalOutboundStatusEnum.two.getValue(), NormalOutboundStatusEnum.three.getValue(),
                            NormalOutboundStatusEnum.four.getValue(), NormalOutboundStatusEnum.six.getValue())
                    .ge(OrderOutboundDo::getCreateTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -7))));
            if (count == 0) {
                dao.updateSend(platformOrderIds, StaticDict.Platform_Order_Status.Three.getValue(), req.getUserId());
                List<OperateRecordDo> operateRecordDos = new ArrayList<>();
                for (Object orderId : platformOrderIds) {
                    OperateRecordDo operateRecordDo = new OperateRecordDo((Long) orderId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_Sync_Send, req.getUserId(), new Date(), "");
                    operateRecordDos.add(operateRecordDo);
                }
                if (!operateRecordDos.isEmpty()) {
                    List<List<OperateRecordDo>> partition = ListUtil.partition(operateRecordDos, 3000);
                    for (List<OperateRecordDo> partList : partition) {
                        rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
                    }
                }
            }
        }
    }


    @Override
    public void getPlatformOrderTrackTemplate(HttpServletResponse response, Long tenantId) throws IOException {
        TemplateExportParams params = new TemplateExportParams(
                "excelTemplates/PlatformOrderTrackNo_Import.xlsx", true);

        response.setCharacterEncoding("UTF-8");
        response.setHeader("content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setHeader("Content-Disposition", "attachment;filename=PlatformOrderTrackNo_Import.xlsx");
        //导出数据
        try (Workbook book = ExcelExportUtil.exportExcel(params, this.buildTemplateSheetData(tenantId))) {
            book.write(response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            response.getOutputStream().flush();
            response.getOutputStream().close();
        }
    }

    private Map<String, Object> buildTemplateSheetData(Long tenantId) {
        //每个sheet的数据对应一个map
        Map<String, Object> sheetMap = new HashMap<>(1);
        //处理第一个sheet(店铺)
        Map<String, Object> channelMap = new HashMap<>(1);
        channelMap.put("tenantId", tenantId);
        List<LcChannelPageRes> list = logisticsChannelService.getList(channelMap);
        sheetMap.put("channelList", list);
        return sheetMap;
    }


    //平台订单直接导入快递单号
    @Override
    public void importTrackNo(MultipartFile file, Long userId, Long companyId, Long tenantId) {
        List<PlatformOrderImportTrackNoVo> importTrackNoVos = null;
        try {
            importTrackNoVos = ExcelUtils.importExcel(file, 1, 0,  PlatformOrderImportTrackNoVo.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        if (importTrackNoVos.isEmpty()) {
            return;
        }
        List<String> platformOrderNos = importTrackNoVos.stream().filter(i -> StringUtils.isNotBlank(i.getChannelCode())).map(PlatformOrderImportTrackNoVo::getPlatformOrderNo).filter(StringUtils::isNotBlank).collect(Collectors.toList());
        if (platformOrderNos.isEmpty()) {
            return;
        }
        //获取物流方式
        List<LogisticsChannelDo> logisticsChannelDos = logisticsChannelService.list(new LambdaQueryWrapper<LogisticsChannelDo>().eq(LogisticsChannelDo::getTenantId, tenantId));
        Map<String, Long> channelMap = logisticsChannelDos.stream().collect(Collectors.toMap(LogisticsChannelDo::getChannelCode, LogisticsChannelDo::getId, (i1, i2) -> i1));
        Map<String, String> carrierMap = logisticsChannelDos.stream().collect(Collectors.toMap(LogisticsChannelDo::getChannelCode, LogisticsChannelDo::getCarrier, (i1, i2) -> i1));

        Map<String, Long> idMap = dao.selectList(new LambdaQueryWrapper<PlatformOrderDo>()
                        .select(PlatformOrderDo::getId, PlatformOrderDo::getPlatformOrderNo)
                        .in(PlatformOrderDo::getPlatformOrderNo, platformOrderNos)
                        .eq(PlatformOrderDo::getCompanyId, companyId)
//                        .ne(PlatformOrderDo::getStatus, StaticDict.Platform_Order_Status.Three.getValue())
                        .ge(PlatformOrderDo::getOrderTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -1000))))
                .stream().collect(Collectors.toMap(PlatformOrderDo::getPlatformOrderNo, PlatformOrderDo::getId, (i1, i2) -> i1));

        List<PlatformOrderTrackDo> trackDos = new ArrayList<>();
        Map<String, List<PlatformOrderImportTrackNoVo>> trackMap = importTrackNoVos.stream().collect(Collectors.groupingBy(PlatformOrderImportTrackNoVo::getPlatformOrderNo));
        List<OperateRecordDo> operateRecordDos = new ArrayList<>();
        for (Map.Entry<String, List<PlatformOrderImportTrackNoVo>> entry : trackMap.entrySet()) {
            String platformOrderNo = entry.getKey();
            List<PlatformOrderImportTrackNoVo> trackNoVos = entry.getValue();
            Long platformOrderId = idMap.get(platformOrderNo);
            if (platformOrderId == null) {
                continue;
            }
            for (PlatformOrderImportTrackNoVo trackNoVo : trackNoVos) {
                if (StringUtils.isBlank(trackNoVo.getTrackNo())) {
                    continue;
                }
                Long channelId = channelMap.get(trackNoVo.getChannelCode());
                if (channelId == null) {
                    continue;
                }
                String carrier = carrierMap.get(trackNoVo.getChannelCode());
                if (StringUtils.isBlank(carrier)) {
                    continue;
                }
                String[] splitTrackArr = trackNoVo.getTrackNo().split(",");
                for (String s : splitTrackArr) {
                    trackDos.add(new PlatformOrderTrackDo(null, platformOrderId, null,
                            null, channelId, carrier, s, userId));
                }
                OperateRecordDo operateRecordDo = new OperateRecordDo(platformOrderId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_import_trackNo, userId, new Date(), trackNoVo.getTrackNo());
                operateRecordDos.add(operateRecordDo);
            }
        }
        //批量插入
        if (!trackDos.isEmpty()) {
            platformOrderTrackDao.insertBatch(trackDos);
            //更新主表快递单号
            List<Object> ids = new ArrayList<>(idMap.values());
            dao.updateTrackNoAndChannelId(ids);
        }
        if (!operateRecordDos.isEmpty()) {
            List<List<OperateRecordDo>> partition = ListUtil.partition(operateRecordDos, 3000);
            for (List<OperateRecordDo> partList : partition) {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
            }
        }
    }


    @Override
    public void export(Map<String, Object> map, HttpServletResponse response) {
        if (StaticDict.Company_Type.Labella.getValue().equals(customer) || StaticDict.Company_Type.Lemooli.getValue().equals(customer)) {
            List<PlatOrderPageRes> list = dao.getList(map);
            if (list.size() > 50000) {
                throw new BizException(SysConstant.File_Export_ToMuch, 50000);
            }
//            List<PlatformOrderExportVo> exportVos = BeanConvert.INSTANCE.platformOrderExportVos(list);
//            String fileName = "平台订单列表导出" + TimeUtils.getCurrentDateFormat("MMddHHmmss");
//            try {
//                ExcelUtils.exportExcel(exportVos, PlatformOrderExportVo.class, fileName, new ExportParams(), response);
//            } catch (IOException e) {
//                throw new RuntimeException(e);
//            }
            CsvExportParams csvParam = new CsvExportParams();
            csvParam.setEncoding("Shift-JIS");
            csvParam.setTextMark("");
            List<PlatformOrderNewExportVo> exportVos = new ArrayList<>();
            List<List<PlatOrderPageRes>> partition = ListUtil.partition(list, 8000);
            for (List<PlatOrderPageRes> pageResList : partition) {
                Map<Long, List<PlatformOrderProductDo>> collect = platformOrderProductDao.selectList(new LambdaQueryWrapper<PlatformOrderProductDo>().in(PlatformOrderProductDo::getOrderId, pageResList.stream().map(PlatOrderPageRes::getId).collect(Collectors.toList())))
                        .stream().collect(Collectors.groupingBy(PlatformOrderProductDo::getOrderId));
                for (PlatOrderPageRes pageRes : pageResList) {
                    StringBuilder address = new StringBuilder();
                    if (StringUtils.isNotBlank(pageRes.getAddressOne())) {
                        address.append(pageRes.getAddressOne());
                    }
                    if (StringUtils.isNotBlank(pageRes.getAddressTwo())) {
                        address.append(pageRes.getAddressTwo());
                    }
                    if (StringUtils.isNotBlank(pageRes.getAddressTri())) {
                        address.append(pageRes.getAddressTri());
                    }
                    List<PlatformOrderProductDo> productDos = collect.get(pageRes.getId());
                    if (productDos == null || productDos.isEmpty()) {
                        continue;
                    }

                    String japanChannelName = pageRes.getChannelCode();
                    if ("yamato_zhai".equals(japanChannelName)) {
                        japanChannelName = "ヤマト（宅急便）";
                    }
                    else if ("yamato_one".equals(japanChannelName) || "yamato_more".equals(japanChannelName)){
                        japanChannelName = "ネコポス";
                    }
                    for (PlatformOrderProductDo productDo : productDos) {
                        String orderTime = null;
                        if (pageRes.getOrderTime() != null) {//pageRes.getOrderTime()
                            orderTime = DateUtils.dateFormatToString(pageRes.getOrderTime(), "yyyy-MM-dd HH:mm:ss");
                        }
                        PlatformOrderNewExportVo exportVo = new PlatformOrderNewExportVo(pageRes.getPlatformOrderNo(), pageRes.getStoreName(), japanChannelName, pageRes.getReceiver(), pageRes.getPostcode(), pageRes.getDistrict(), pageRes.getCityCode(), address.toString().replaceAll(",", ""), pageRes.getTelephone(), pageRes.getDeliveryDate(), pageRes.getDeliveryTimeName(), pageRes.getTrackNo(), orderTime);
                        exportVo.setPlatformSku(productDo.getPlatformSku());
                        exportVo.setPlatformQty(productDo.getPlatformQty());
                        exportVo.setSku(productDo.getSku());
                        exportVo.setQty(productDo.getQty());
                        if (StringUtils.isNotBlank(productDo.getPlatformProductName())) {
                            exportVo.setPlatformProductName(productDo.getPlatformProductName().replaceAll(",", ""));
                        }
                        exportVo.setDelvdateInfo(productDo.getDelvdateInfo());
                        exportVos.add(exportVo);
                    }
                }
            }
            CsvUtils.exportCsv(csvParam, PlatformOrderNewExportVo.class, exportVos, "平台订单列表导出" + TimeUtils.getCurrentDateFormat("MMddHHmmss")+".csv", response);



        } else {
            this.exportKK(map, response);
        }

    }



    public void exportKK(Map<String, Object> map, HttpServletResponse response) {
        List<PlatOrderPageRes> list = dao.getList(map);
        if (list.size() > 20000) {
            throw new BizException(SysConstant.File_Export_ToMuch, 20000);
        }

        List<PlatformOrderKkExportVo> kkExportVos = new ArrayList<>();
        for (PlatOrderPageRes platOrderPageRes : list) {
            PlatformOrderKkExportVo kkExportVo = new PlatformOrderKkExportVo();
            if (StringUtils.isNotBlank(platOrderPageRes.getSkus())) {
                String sku = platOrderPageRes.getSkus().split(";")[0];
                kkExportVo.setSku1(sku.split("\\*")[0]);
                kkExportVo.setQuantity1(sku.split("\\*")[1]);

                if (platOrderPageRes.getSkus().split(";").length > 1) {
                    String string = platOrderPageRes.getSkus().split(";")[1];
                    kkExportVo.setSku2(string.split("\\*")[0]);
                    kkExportVo.setQuantity2(string.split("\\*")[1]);
                }
                if (platOrderPageRes.getSkus().split(";").length > 2) {
                    String string = platOrderPageRes.getSkus().split(";")[2];
                    kkExportVo.setSku3(string.split("\\*")[0]);
                    kkExportVo.setQuantity3(string.split("\\*")[1]);
                }
                if (platOrderPageRes.getSkus().split(";").length > 3) {
                    String string = platOrderPageRes.getSkus().split(";")[3];
                    kkExportVo.setSku4(string.split("\\*")[0]);
                    kkExportVo.setQuantity4(string.split("\\*")[1]);
                }

                if (platOrderPageRes.getSkus().split(";").length > 4) {
                    String string = platOrderPageRes.getSkus().split(";")[4];
                    kkExportVo.setSku5(string.split("\\*")[0]);
                    kkExportVo.setQuantity5(string.split("\\*")[1]);
                }
            }
            kkExportVo.setPostcode(platOrderPageRes.getPostcode());
            kkExportVo.setProvinceCode(platOrderPageRes.getProvinceCode());
            kkExportVo.setDistrict(platOrderPageRes.getDistrict());
            kkExportVo.setCityCode(platOrderPageRes.getCityCode());
            StringBuilder address = new StringBuilder();
            address.append(platOrderPageRes.getAddressOne());
            if (StringUtils.isNotBlank(platOrderPageRes.getAddressTwo())) {
                address.append("\r\n").append(platOrderPageRes.getAddressTwo());
            }
            if (StringUtils.isNotBlank(platOrderPageRes.getAddressTri())) {
                address.append("\r\n").append(platOrderPageRes.getAddressTri());
            }
            kkExportVo.setAddressOne(address.toString());
            kkExportVo.setReceiver(platOrderPageRes.getReceiver());
            kkExportVo.setTelephone(platOrderPageRes.getTelephone());
            kkExportVo.setDeliveryDate(platOrderPageRes.getDeliveryDate());
            kkExportVo.setDeliveryTimeName(platOrderPageRes.getDeliveryTimeName());
            if (StringUtils.isNotBlank(kkExportVo.getDeliveryTimeName())) {
                kkExportVo.setDeliveryTimeName(kkExportVo.getDeliveryTimeName().replaceAll("-", ""));
            }
            kkExportVo.setPlatformOrderNo(platOrderPageRes.getPlatformOrderNo());
            kkExportVo.setRemark(platOrderPageRes.getRemark());
            kkExportVos.add(kkExportVo);
        }
        String fileName = "平台订单列表导出" + TimeUtils.getCurrentDateFormat("MMddHHmmss");
        try {
            ExcelUtils.exportExcel(kkExportVos, PlatformOrderKkExportVo.class, fileName, new ExportParams(), response, "xls");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }



    //平台订单 重新映射功能
    @Override
    public void cancelMatchSysProduct(List<Long> ids, Long userId, Long companyId) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        List<PlatformOrderDo> orderDos = dao.selectList(new LambdaQueryWrapper<PlatformOrderDo>()
                .select(PlatformOrderDo::getId, PlatformOrderDo::getStatus)
//                        .isNotNull(PlatformOrderDo::getSku)
                        .eq(PlatformOrderDo::getStatus, StaticDict.Platform_Order_Status.Zero.getValue())
                .eq(PlatformOrderDo::getCompanyId, companyId).in(PlatformOrderDo::getId, ids));
        if (CollUtil.isEmpty(orderDos)) {
            return;
        }
        //获取子表
        List<PlatformOrderProductDo> itemDos = platformOrderProductDao.selectList(new LambdaQueryWrapper<PlatformOrderProductDo>()
               .in(PlatformOrderProductDo::getOrderId, ids));
        if (CollUtil.isEmpty(itemDos)) {
            return;
        }
        List<Long> toDeleteProductIds = itemDos.stream().filter(item -> item.getSkuType() == 0).map(PlatformOrderProductDo::getId).collect(Collectors.toList());
        if (!toDeleteProductIds.isEmpty()) {
            //删除
            platformOrderProductDao.deleteBatchIds(toDeleteProductIds);
        }
        List<Long> toUpdateProductIds = itemDos.stream().filter(item -> item.getSkuType() == 1 && item.getProductId() != null).map(item -> item.getId()).collect(Collectors.toList());
        List<Long> toUpdateOrderIds = itemDos.stream().filter(item -> item.getSkuType() == 1 && item.getProductId() != null).map(item -> item.getOrderId()).distinct().collect(Collectors.toList());

        if (!toUpdateProductIds.isEmpty()) {
            LambdaUpdateWrapper<PlatformOrderProductDo> updateWrapper = new LambdaUpdateWrapper<PlatformOrderProductDo>()
                    .set(PlatformOrderProductDo::getProductId, null)
                    .set(PlatformOrderProductDo::getSku, null)
                    .set(PlatformOrderProductDo::getQty, null)
                    .in(PlatformOrderProductDo::getId, toUpdateProductIds);
            platformOrderProductDao.update(null, updateWrapper);
        }
        if (!toUpdateOrderIds.isEmpty()) {
            LambdaUpdateWrapper<PlatformOrderDo> updateWrapper = new LambdaUpdateWrapper<PlatformOrderDo>()
                    .set(PlatformOrderDo::getSku, null)
                    .in(PlatformOrderDo::getId, toUpdateOrderIds);
            dao.update(null, updateWrapper);
        }
    }

}
